Keep a terminated reserved connection out of the pool (fixes #1199) - #1240
Open
Mariomarquezt wants to merge 1 commit into
Open
Mariomarquezt wants to merge 1 commit into
Mariomarquezt wants to merge 1 commit into
Conversation
When the server terminates the backend of a reserved connection, onclose moves the connection to the closed queue, and may reconnect it at once for a waiting query. The ReservedSql handle still pointed at it: - later queries on the handle called execute() on a connection with a null socket, so nextWrite() threw an uncaught TypeError and the query never settled; - release() called onopen() and put the dead connection in the open queue, so the next pool query hung (porsager#1199). onclose now marks the handle closed. Its queued queries are rejected, later queries reject with the close error, and release() leaves the connection with the pool, which reconnects it as usual. Fixes porsager#1199
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1199.
The defect
When the server terminates the backend of a reserved connection,
onclose()moves the connection to theclosedqueue and setsc.reserved = null. It can also reconnect it at once for a waiting query. TheReservedSqlhandle does not know any of this:c.execute()on a connection whose socket isnull.nextWrite()throws an uncaughtTypeError: Cannot read properties of null (reading 'write'), and the query never settles (the nextWrite() throws an uncaughtException when a reserved connection's backend dies #1208 symptom, reached throughreserve()).release()callsonopen(c)and puts the dead connection in theopenqueue. The next pool query goes to it and hangs (bug: pool never recovers after releasing a reserved connection whose backend was terminated. #1199).The fix
onclose()calls aclosedhook on the reservation before it clearsc.reserved. The hook records the close error and rejects the handle's own overflow queue. After that, the handle is dead for good:CONNECTION_CLOSED);release()does nothing, because the connection already belongs to the pool'sclosedqueue, which reconnects it as usual.Healthy reservations do not change.
Tests
Two new tests in
tests/index.jsagainst a real server:On a CI-like setup (PostgreSQL 17 with the workflow's
pg_hba.conf,ssl=on,wal_level=logical,max_prepared_transactions=100, and a second server on 5433; Node 20):node tests/index.jsdies with the uncaughtTypeErrorabove;test:esmand intest:cjs(264 existing + 2 new).Deno was not run locally.
Related open PRs
These fix nearby parts of the same close path and do not overlap with this change: #1209 (guard
nextWrite()itself), #1215 (reject transaction work after its connection closes), #1229 (a queuedreserve()stranded by a termination). This PR only covers the reserved handle andrelease().We have run this change as a local patch against 3.4.9 in production since 2026-09-30.
🤖 Generated with Claude Code