Share Prime sandbox clients across concurrent runtimes - #2411
Conversation
| if clientPool is None: | ||
| clientPool = PrimeClientPool(loop=loop, client=AsyncSandboxClient()) | ||
| clientPools[loop] = clientPool | ||
| clientPool.users += 1 |
There was a problem hiding this comment.
🟡 Medium runtimes/prime.py:176
A provisioning failure leaves clientPool.users incremented permanently, so after the other runtimes tear down the shared AsyncSandboxClient remains in clientPools and its HTTP resources are never closed. _serve only registers runtime.stop after await runtime.start() succeeds, so this failed start path cannot reach teardown(); roll back the pool lease in the start exception path and close/remove the pool when that rollback reaches zero.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @verifiers/v1/runtimes/prime.py around line 176:
A provisioning failure leaves `clientPool.users` incremented permanently, so after the other runtimes tear down the shared `AsyncSandboxClient` remains in `clientPools` and its HTTP resources are never closed. `_serve` only registers `runtime.stop` after `await runtime.start()` succeeds, so this failed `start` path cannot reach `teardown()`; roll back the pool lease in the `start` exception path and close/remove the pool when that rollback reaches zero.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces client pooling with lease counting for Prime sandbox clients - a significant runtime behavior change to resource management. Additionally, unresolved comments identify a resource leak when Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7661ba728d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pool = client_pools.get(loop) | ||
| if pool is None: | ||
| pool = client_pools[loop] = PrimeClientPool(client=AsyncSandboxClient()) | ||
| pool.leases += 1 |
There was a problem hiding this comment.
Release the pooled lease when startup fails
When a non-colocated MCP server uses Prime and runtime.start() raises, _serve registers runtime.stop only after startup returns (verifiers/v1/mcp/launch.py:372-374), so this increment is never balanced. The module-level pool then strongly retains the event loop and client with a permanently positive lease count; subsequent runtimes reuse that poisoned pool, and their final teardown never removes or closes it. Release the lease on failed startup or ensure teardown is registered before awaiting start().
Useful? React with 👍 / 👎.
Overview
Share one Prime Sandboxes async client across active Prime runtimes on the same event loop. This lets the SDK coalesce concurrent sandbox and background-job status polls into its bounded batch requests.
Details
PrimeClientPool.Note
Medium Risk
Changes shared client lifecycle and teardown for remote sandboxes. Incorrect lease counting or loop-keyed global state could close a client too early or leak it.
Overview
Shares one Prime
AsyncSandboxClientacross concurrentPrimeRuntimes on the same event loop so the SDK can batch status polls.Adds a reference-counted
PrimeClientPool.startleases the loop’s client instead of creating a new one;teardownstill deletes each sandbox independently, then drops the lease andacloses only when the last runtime on that loop exits.Reviewed by Cursor Bugbot for commit 7661ba7. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Share
AsyncSandboxClientacrossPrimeRuntimeinstances per event loopPrimeClientPooland aclient_poolsdict mappingasyncioevent loops to sharedAsyncSandboxClientinstances and lease counts.PrimeRuntime.startnow reuses an existing client for the current event loop or creates a new one, incrementing the pool's lease counter.PrimeRuntime.teardowndecrements the lease counter and only callsclient.aclose()when the last runtime on that loop tears down.PrimeRuntime.teardownno longer unconditionally closes the client; incorrect lease tracking could leak or prematurely closeAsyncSandboxClientinstances.Macroscope summarized 7661ba7.