Skip to content

tbench2 env server: enable idle-session reaper to reclaim leaked slots#1000

Open
Shi-Dong wants to merge 1 commit into
huggingface:mainfrom
Shi-Dong:shi/openenv-session-reaper-timeout
Open

tbench2 env server: enable idle-session reaper to reclaim leaked slots#1000
Shi-Dong wants to merge 1 commit into
huggingface:mainfrom
Shi-Dong:shi/openenv-session-reaper-timeout

Conversation

@Shi-Dong

@Shi-Dong Shi-Dong commented Jul 22, 2026

Copy link
Copy Markdown

What

The tbench2_env server now enables the core idle-session reaper by passing an explicit ConcurrencyConfig(max_concurrent_envs=..., session_timeout=...) to create_app, instead of the bare max_concurrent_envs= argument. A new SESSION_IDLE_TIMEOUT_S env var (default 3600) controls the reap interval.

Why

The /mcp WebSocket handler releases its session slot and Docker container only in a finally block, which runs solely on a clean socket close. Half-open or uncleanly-dropped connections never raise WebSocketDisconnect, so receive_text() blocks forever, the finally never runs, and the session slot + its Docker container leak.

Under sustained load these leaks accumulate over roughly a day until all MAX_CONCURRENT_ENVS slots are permanently held. New episodes then deadlock on CAPACITY_REACHED and the only recovery is a manual env-server restart.

Passing a bare max_concurrent_envs maps to ConcurrencyConfig(session_timeout=None) in the core server, which disables _reap_idle_sessions. Supplying an explicit session_timeout re-enables the reaper so stale sessions are evicted and their containers reclaimed automatically, without operator intervention.

Notes

  • Default SESSION_IDLE_TIMEOUT_S=3600 preserves existing behavior for short-lived sessions while bounding leaked slots.
  • Single-file change scoped to envs/tbench2_env/server/app.py; no change to the core server or to the on-the-wire protocol.

Note

Low Risk
Single-file server bootstrap change with a conservative default timeout; no protocol or core server edits.

Overview
The tbench2_env server now passes an explicit ConcurrencyConfig to create_app (with max_concurrent_envs and session_timeout) instead of only max_concurrent_envs, which turns on the core idle-session reaper that was previously off when session_timeout was unset.

A new SESSION_IDLE_TIMEOUT_S env var (default 3600) sets how long a session can sit idle before it is reaped so its WebSocket slot and Docker container are released. That targets leaks from half-open /mcp WebSocket connections that never hit a clean disconnect, which could otherwise hold all MAX_CONCURRENT_ENVS slots until a manual restart.

Reviewed by Cursor Bugbot for commit adc5d44. Bugbot is set up for automated code reviews on this repo. Configure here.

The /mcp WebSocket handler releases its session slot and Docker container
only in a finally block, which runs solely on a clean socket close.
Half-open or uncleanly-dropped connections never raise WebSocketDisconnect,
so receive_text() blocks forever, finally never runs, and the slot +
container leak. Over ~20-24h these accumulate until all MAX_CONCURRENT_ENVS
slots are held and new episodes deadlock on CAPACITY_REACHED, requiring a
manual env-server reset.

create_app was called with a bare max_concurrent_envs, which the core
server maps to ConcurrencyConfig(session_timeout=None) -> the idle-session
reaper is disabled. Pass an explicit ConcurrencyConfig with session_timeout
instead (SESSION_IDLE_TIMEOUT_S env var, default 3600s) so
_reap_idle_sessions runs and evicts stale sessions, reclaiming their
containers automatically.
@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@nblintao nblintao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants