The app engine pool is sized for the run queue, not a lone request - #277
Merged
czpython merged 2 commits intoAug 17, 2026
Conversation
Twenty concurrent scout runs exhausted the application engine: it carried SQLAlchemy's default QueuePool (5 + 10 overflow) while both DBOS engines are tuned to twenty, and one engine serves every run's steps plus request handling. The sixteenth waiter timed out at five seconds and failed its run. The pool is now explicit — twenty plus ten overflow — matching the width the queue actually runs at. pool_timeout stays low: a checkout wait blocks the event loop, so the fix is capacity, not patience. The queue itself stays uncapped deliberately: a parked run holds its queue slot, so a concurrency cap could starve the appliance behind a handful of runs waiting on humans.
Overflow connections open on demand and close on return, so a high ceiling costs nothing at idle. Fifty keeps the appliance — with both DBOS engines at twenty — inside Postgres's default hundred.
czpython
enabled auto-merge (squash)
August 17, 2026 17:52
czpython
deleted the
commonzenpython/eng-863-app-db-engine-pool-is-sqlite-era-default-exhausts-under
branch
August 17, 2026 17:53
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.
A batch of twenty concurrent scout runs exhausted the application database engine.
create_engine_from_urlset no pool sizing, so it carried SQLAlchemy's defaults — 5 connections plus 10 overflow — while both DBOS engines are explicitly tuned to 20. One application engine backs every concurrent run's steps and all request handling at once; the sixteenth waiter timed out after five seconds and failed its run withQueuePool limit of size 5 overflow 10 reached.The pool is now explicit:
pool_size=20, max_overflow=30— a modest steady pool with overflow doing the burst work. Overflow connections open on demand and close on return, so the ceiling is high while idle cost is not. Ceiling 50 keeps the appliance, with both DBOS engines at 20, inside Postgres's default 100 connections; steps hold a connection for milliseconds around long agent calls, so 50 simultaneous checkouts implies a fleet far larger than any today.pool_timeoutstays at five seconds — a checkout wait blocks the event loop, so the answer to contention is capacity, not longer waits.Capping the run queue instead was considered and rejected: a parked run still occupies its queue slot while it waits on a human, so a concurrency cap would let a handful of parked gates starve every other run on the appliance. The pool is the safe control point.
This sizing covers the width the queue runs at today; it moves the ceiling rather than abolishing it. The structural end state is the planned async-engine migration, where a connection checkout awaits instead of blocking the loop — pool exhaustion then becomes backpressure and the pool itself is the throttle. Until then the constant is honest: matched to the DBOS engines, with request-handling headroom.