WIP: executor — pool TypeScript runner processes per harness module#125
Draft
akrentsel wants to merge 1 commit into
Draft
WIP: executor — pool TypeScript runner processes per harness module#125akrentsel wants to merge 1 commit into
akrentsel wants to merge 1 commit into
Conversation
TypeScriptExecutor kept one Node runner process per module_path and held its mutex for the whole turn, serializing every turn that shares a harness module across all conversations and agents. Replace that with a per-module RunnerPool: a semaphore budget over a LIFO free-list of warm runners. Checkout transfers ownership of a runner to the turn (the mutex is gone); a clean turn checks it back in warm, a failed turn drops it (the guest already exits on error). Idle runners expire after a TTL via a one-shot per-check-in timer holding a Weak to the pool, so dropping the executor reaps them immediately and a quiescent pool drains to zero. Size via EXO_TS_RUNNER_POOL (default 4, clamped to 256). Adds unit tests (fake spawner) and an ignored end-to-end test driving real Node runners. Design: docs/ts-runner-pool-design.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator
Author
|
Please don't review yet – am editing still. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft / WIP — opening for early review of the approach.
Problem
TypeScriptExecutorkept one Node runner process permodule_pathand held its mutex for the whole turn (model latency included), serializing every turn that shares a harness module — across all conversations and agents. The agent-scale eval measured this as the dominant throughput ceiling and worked around it with K module-path symlinks round-robin'd by the driver (multiplies the map key rather than fixing the executor; round-robin also idles a slow turn's slot).Change
Replace the per-runner mutex with a per-module
RunnerPool: a semaphore budget over a LIFO free-list of warm runners.acquirehands the runner to the turn; the mutex is gone. A clean turn checks it back in warm; a failed turn drops it (the guest already exits on error, so "turn failed" == "process dead").RUNNER_IDLE_TTL(5 min) via a one-shot per-check-in timer holding aWeakto the pool, so dropping the executor reaps them immediately and a quiescent pool drains to zero.EXO_TS_RUNNER_POOL(default 4, clamped to 256).runner.ts) / exoharness changes.Design + semantics:
docs/ts-runner-pool-design.md.Not in scope (deliberate)
Tests
--ignored): 4 concurrent turns on one module → 4 distinct runner PIDs, overlapping, + warm reuse.Measured (agent-scale, synthetic mock model, single box)
Open / follow-ups
runnersmap entry is never removed (minor; module set normally fixed).pinned+ env clamp).🤖 Draft generated with assistance from Claude.