fix: disable autoconnect and set pool timeout on PooledPostgresqlDatabase (#80) #87
No reviewers
Labels
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cal/major-domo-database#87
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "issue/80-disable-autoconnect-and-set-pool-timeout-on-pooled"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #80
Summary
Two connection pool reliability fixes for
PooledPostgresqlDatabase:timeout=0→timeout=5(app/db_engine.py): Pool now returns an error after 5 seconds if all 20 connections are exhausted, instead of hanging indefinitely. This surfaces load problems as visible 503-level errors rather than silent worker hangs.autoconnect=True→autoconnect=False(app/db_engine.py): Disables implicit connection acquisition on model attribute access. Connection lifecycle is now explicit and predictable.HTTP middleware (
app/main.py): Addeddb_connection_middlewarethat callsdb.connect(reuse_if_open=True)at request start anddb.close()in afinallyblock at request end. This is the required companion toautoconnect=False— existing route handlers already calldb.close()themselves, so the middleware's final close is a safe no-op for those handlers (Peewee pool handles double-close gracefully via theis_closed()guard).Files Changed
app/db_engine.py—timeout=5,autoconnect=Falseapp/main.py— importdb, adddb_connection_middlewareTest Results
No test suite configured (per CLAUDE.md). Changes verified by code review.
Other observations
'sba_dev_password_2024'ondb_engine.py:21was addressed by PR #84 but the fix doesn't appear to be in HEAD — may need a re-apply after that PR's branch diverged.AI Code Review
Files Reviewed
app/db_engine.py(modified)app/main.py(modified)Findings
Correctness
timeout=5: Correct. Peewee's pooltimeoutparameter controls how long to wait for an available connection.0= infinite wait;5= raisepeewee.OperationalErrorafter 5 seconds. This surfaces pool exhaustion as a visible error instead of a silent worker hang.autoconnect=False: Correct. Disables implicit connection acquisition on model attribute access. The middleware is the required companion — this pair is the standard pattern for explicit lifecycle management.db.connect(reuse_if_open=True)is safe — no error if already connected. Theif not db.is_closed()guard infinallycorrectly handles the ~130 existingdb.close()calls in route handlers (double-close becomes a no-op).call_nextraises,responseis unassigned, but the exception propagates pastreturn response— noNameErrorrisk. Thefinallyblock still cleans up the connection correctly.from .db_engine import db: Correct relative import.dbis defined at module level indb_engine.py.Security
db_engine.py:21still haspassword=os.environ.get('POSTGRES_PASSWORD', 'sba_dev_password_2024')— the PR author notes this correctly as a diverged branch issue from PR #84. Out of scope here.Style & Conventions
app = FastAPI(...)andlogger.info("Starting up now...")) is correct. FastAPI middleware registration order relative to router inclusion has no effect.db.connect(),db.close()) inside anasyncmiddleware will block the event loop momentarily. This is the unavoidable tradeoff with Peewee's synchronous driver and is the standard accepted pattern for this stack. Not a blocker.Suggestions
is_closed()guard. Both are fine — the guard is more defensive and slightly clearer. No change needed.Verdict: APPROVED
Clean, well-reasoned implementation. The three changes (
timeout=5,autoconnect=False, middleware) work correctly as a unit. Connection lifecycle is now explicit and predictable, pool exhaustion surfaces as a visible error, and thefinally+is_closed()guard ensures the connection is always returned to the pool. No issues found.Automated review by Claude PR Reviewer
Checkout
From your project repository, check out a new branch and test the changes.