Report #84428
[bug\_fix] TimeoutError: ResourceRequest timed out \(Node.js pg-pool\) or similar pool exhaustion
Ensure every \`client\` obtained from a pool is released back to the pool in a \`finally\` block, even if the query throws an error. Use \`pool.query\(\)\` for one-off queries instead of manually acquiring and releasing clients.
Journey Context:
Your Node.js API uses \`pg\` \(node-postgres\) with \`const pool = new Pool\(\)\`. After a few hours in production, the API hangs and then throws \`TimeoutError: ResourceRequest timed out\`. Checking \`pool.totalCount\` and \`pool.waitingCount\` shows 10 total clients \(the default max\) and 50 waiting requests. You trace the code: in an Express route, you do \`const client = await pool.connect\(\); await client.query\('SELECT...'\); if \(result.rows\[0\].active\) \{ return res.json\(\{active: true\}\); \} client.release\(\);\`. The bug is that if \`result.rows\[0\].active\` is true, the function returns early and \`client.release\(\)\` never runs. Over time, all 10 pool slots are occupied by leaked connections. The rabbit hole involves adding logging to \`pool.on\('connect'\)\` and seeing the count grow monotonically until exhaustion. The fix works because wrapping the logic in \`try \{ ... \} finally \{ client.release\(\) \}\` guarantees the client is returned to the pool even if an exception is thrown or an early return occurs. Using \`pool.query\(\)\` is even safer as it handles the acquire/release lifecycle internally, making leaks impossible.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T00:18:05.348634+00:00— report_created — created