feat(producer): add request-level render concurrency semaphore - #232
Merged
Conversation
jrusso1020
force-pushed
the
feat/render-concurrency-semaphore
branch
from
April 9, 2026 17:21
7e27e82 to
abdfeee
Compare
miguel-heygen
force-pushed
the
fix/beginframe-retry-on-pending
branch
from
April 9, 2026 17:27
18869f4 to
aab2d2c
Compare
miguel-heygen
approved these changes
Apr 9, 2026
jrusso1020
force-pushed
the
feat/render-concurrency-semaphore
branch
from
April 9, 2026 17:54
abdfeee to
8842a95
Compare
Add a FIFO semaphore to limit concurrent renders in the producer server, preventing Chrome CPU contention that causes beginFrame failures. - New Semaphore utility class (packages/producer/src/utils/semaphore.ts) - Both blocking render and SSE renderStream handlers acquire/release the semaphore - SSE stream sends a "queued" event when request must wait - New GET /render/queue endpoint exposes active/queued render counts - Configurable via HandlerOptions.maxConcurrentRenders or PRODUCER_MAX_CONCURRENT_RENDERS env var (default: 2) - New --max-concurrent-renders CLI flag (1-10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jrusso1020
force-pushed
the
feat/render-concurrency-semaphore
branch
from
April 9, 2026 17:55
8842a95 to
458ee97
Compare
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.
What
Add a request-level FIFO semaphore to the producer server that limits how many renders execute simultaneously.
Why
Parallel renders cause Chrome CPU contention — when multiple Chrome instances compete for CPU,
beginFramecalls fail because the compositor can'tproduce frames within the deadline. This semaphore ensures renders are queued FIFO so only N renders run at once (default 2), preventing the contention
that triggers beginFrame timeouts even with the retry logic from #230.
How
packages/producer/src/utils/semaphore.ts): Simple async counting semaphore with FIFO queue.acquire()returns a release function; callers hold the slot until they callrelease().POST /render): Acquires the semaphore after input validation but before starting the render. Releases infinallyso the slot is freed even on errors.POST /render/stream): Same acquire/release pattern. Additionally sends a"queued"SSE event if the request must wait, so clients know their position.GET /render/queue): Returns{ maxConcurrentRenders, activeRenders, queuedRenders }for observability.HandlerOptions.maxConcurrentRendersoption,PRODUCER_MAX_CONCURRENT_RENDERSenv var (default: 2), and--max-concurrent-rendersCLI flag (1-10).Test plan
maxConcurrentRenders=2, verify only 2 execute at a timeGET /render/queuereturns correct counts during concurrent renders"queued"event when semaphore is fullrelease()fires infinallyeven when render errors — no semaphore leak--max-concurrent-rendersCLI flag validates range 1-10