Premier League Predictor: FastAPI & PostgreSQL — Chapter 11, Exercise 2 ==================================================== TASK Explain why four gunicorn workers running with SQLAlchemy's default pool_size/max_overflow settings can collectively open up to 60 connections to PostgreSQL, not 15, and calculate the real total after applying this chapter's own pool_size=5, max_overflow=2 fix. SOLUTION SQLAlchemy's own default pool settings allow a single engine to open up to pool_size (5) + max_overflow (10) = 15 real connections at genuine peak load. That 15-connection ceiling applies PER ENGINE — and database.py's own engine = create_engine(DATABASE_URL) line runs once per Python process, not once for the whole deployment. gunicorn -w 4 starts four entirely separate operating system processes, each running its own independent copy of the application, each importing database.py independently, and each therefore creating its own separate engine object with its own separate connection pool. The four workers don't share one pool between them — there are genuinely four distinct pools, each capable of reaching its own 15-connection ceiling under load. Four workers × 15 connections per worker = up to 60 real connections to PostgreSQL at once, not 15. After applying pool_size=5, max_overflow=2: each worker's own ceiling becomes 5 + 2 = 7 connections. Four workers × 7 connections per worker = up to 28 real connections total at genuine peak — comfortably under PostgreSQL's own default max_connections of 100, with real headroom left over for anything else (an admin tool, a monitoring agent) connecting to the same database. WHY THIS WORKS AS AN ANSWER ---------------------------- It correctly identifies that the per-engine ceiling is genuinely per-process, not per-deployment, explains why gunicorn's multi-process model multiplies that ceiling by the worker count, and performs the exact same real multiplication for the chapter's own fixed configuration to arrive at the correct 28-connection total.