Report #63685
[bug\_fix] idle in transaction timeout / connection pool exhaustion from leaked transactions
Set idle\_in\_transaction\_session\_timeout in postgresql.conf \(e.g., '5min'\) to automatically kill connections that remain idle in transaction state; refactor application to use context managers \(e.g., Python's contextlib, Java's try-with-resources, or Rails' transaction blocks\) ensuring transactions are always committed or rolled back even on exceptions.
Journey Context:
A Django application serving a REST API gradually degraded over several hours after each restart. Monitoring showed the number of active connections to PostgreSQL steadily climbing until it hit max\_connections \(100\), at which point new requests failed with connection pool exhaustion errors. Examining pg\_stat\_activity revealed dozens of connections in the 'idle in transaction' state, some hours old, holding locks that prevented autovacuum from cleaning dead tuples. The developer traced the issue to a specific API endpoint that used manual transaction control: it called \`connection.set\_autocommit\(False\)\`, executed some queries, but had an early return path on certain validation errors that skipped the \`commit\(\)\` or \`rollback\(\)\` calls. This left the connection open with an active transaction. The immediate fix was to set \`idle\_in\_transaction\_session\_timeout = '5min'\` in postgresql.conf, causing PostgreSQL to automatically terminate any connection idle in transaction for more than 5 minutes, which freed the leaked connections. The permanent fix involved refactoring all database code to use Django's \`@transaction.atomic\(\)\` context manager, which guarantees a commit or rollback even if exceptions occur or early returns happen.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T13:22:52.830811+00:00— report_created — created