fix(db): reset the migration client's session before it re-enters the pool (#12)
ensureSchema borrows a client from the shared 20-slot pool and, on purpose,
turns OFF that session's statement_timeout and
idle_in_transaction_session_timeout and sets lock_timeout = '5s'. All three are
SESSION-scoped, and the client is then released back into the pool without a
reset.
That leak is permanent for the connection's lifetime:
- pg-pool's release() does not reset session state (pg-pool/index.js
_release just re-attaches the idle listener and requeues the client).
- node-postgres sends the pool's statement_timeout / lock_timeout /
idle_in_transaction_session_timeout in the connection's STARTUP PACKET
(pg/lib/client.js), so they are applied once at connect and never
re-applied on checkout.
So after every boot, one of the 20 pooled connections serves ordinary API
traffic with the pool's runaway-query guards inverted:
- statement_timeout is 0 instead of 60s. That is the guard db/pool.ts
documents as the reason a single un-indexed hot query once held all 20
slots and 503-ed the API; on this connection a runaway pins its slot
indefinitely again.
- idle_in_transaction_session_timeout is 0, so a leaked transaction holds
the slot open forever.
- lock_timeout is 5s for ordinary writes, which abort with 55P03
lock_not_available instead of waiting — sporadic 500s that land on
roughly 1 in 20 requests and are near-impossible to reproduce.
Reset the session in the same breath as handing the slot back, which is the
reasoning already applied to the advisory lock a few lines above ("lets the
conn re-enter the pool with no lock state — cleaner"). A failed RESET still
releases: losing a pool slot forever would be worse than a stale session, and
the pool discards a broken connection on its own. X
Xialie Zhuang committed
05b0ffca40dee19e7bf3fd145eb9010cbd6e0151
Parent: 01e954d
Committed by GitHub <noreply@github.com>
on 8/19/2026, 5:26:18 AM