Keep long tool calls from starving the worker pool #24

Merged
Phil merged 1 commit from fix/long-call-slots into main 2026-09-19 14:00:37 +00:00
Owner

Why

The shared hub hung twice on 2026-09-19. Every forgejo call timed out, including get_forgejo_mcp_server_version. Root cause (evidence in #23): mcp-go's stdio server has 5 tool workers, wait_for_run holds one for up to 30 min, and abandoned calls are never cancelled. At both restarts, 6 or 7 wait_for_run calls were in flight (wait cancelled by caller (context done) × 7 at 15:22:33 and × 6 at 15:53:27 CEST).

What

  • pkg/admission: long-running tools (wait_for_run, list_workflow_runs, list_run_jobs) share 16 slots. When all are taken, the next long call is rejected immediately with a clear message instead of occupying a worker.
  • ServeStdio now runs 64 workers (default was 5), so at least 48 are always free for short calls.
  • The SDK client gets the same 60 s request timeout the raw HTTP client already had. The SDK default had none.

Proof

  • New stdio-level test TestShortCallAnswersWhileLongSlotsAreFull: it holds 16 long calls, sends 8 surplus calls (all rejected), then checks that get_forgejo_mcp_server_version answers in under 2 s. It fails against the old setup (5 workers, no limit: no response to request 2 within 2s) and passes with the fix.
  • go test ./... passes.

Closes #23
Refs Philflow/auto-issue-orchestrator#215

🤖 Generated with Claude Code

## Why The shared hub hung twice on 2026-09-19. Every forgejo call timed out, including `get_forgejo_mcp_server_version`. Root cause (evidence in #23): mcp-go's stdio server has 5 tool workers, `wait_for_run` holds one for up to 30 min, and abandoned calls are never cancelled. At both restarts, 6 or 7 `wait_for_run` calls were in flight (`wait cancelled by caller (context done)` × 7 at 15:22:33 and × 6 at 15:53:27 CEST). ## What - `pkg/admission`: long-running tools (`wait_for_run`, `list_workflow_runs`, `list_run_jobs`) share 16 slots. When all are taken, the next long call is rejected immediately with a clear message instead of occupying a worker. - `ServeStdio` now runs 64 workers (default was 5), so at least 48 are always free for short calls. - The SDK client gets the same 60 s request timeout the raw HTTP client already had. The SDK default had none. ## Proof - New stdio-level test `TestShortCallAnswersWhileLongSlotsAreFull`: it holds 16 long calls, sends 8 surplus calls (all rejected), then checks that `get_forgejo_mcp_server_version` answers in under 2 s. It **fails** against the old setup (5 workers, no limit: `no response to request 2 within 2s`) and passes with the fix. - `go test ./...` passes. Closes #23 Refs Philflow/auto-issue-orchestrator#215 🤖 Generated with [Claude Code](https://claude.com/claude-code)
One stdio process serves every Claude session behind the shared hub.
mcp-go runs tools/call on a pool of 5 workers, wait_for_run holds one
for up to 30 min, and a call the client abandoned is never cancelled:
mcp-proxy does not forward notifications/cancelled and mcp-go v0.44
would ignore it. On 2026-09-19 six to seven concurrent wait_for_run
calls held every worker and all other calls queued until restart.

The pool now has 64 workers, and long-running tools share 16 slots.
When those are full the next long call is rejected at once instead of
taking a worker, so short calls always find one. The SDK client also
gets the 60 s request timeout the raw client already had; its default
http.Client had none, so a stalled read could hold a worker forever.

The new stdio-level test fails against the old setup (5 workers, no
limit) and passes with the fix.

Closes #23
Refs Philflow/auto-issue-orchestrator#215

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Phil merged commit cef894e851 into main 2026-09-19 14:00:37 +00:00
Phil deleted branch fix/long-call-slots 2026-09-19 14:00:38 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Phil/forgejo-mcp!24
No description provided.