Repository navigation
Open
Description
The current implementation simply leaves the backend to hang.
Lines 480 to 509 in 60d8df6
| if (readTimeout) { | |
| queryCallback = query.callback | |
| readTimeoutTimer = setTimeout(() => { | |
| var error = new Error('Query read timeout') | |
| process.nextTick(() => { | |
| query.handleError(error, this.connection) | |
| }) | |
| queryCallback(error) | |
| // we already returned an error, | |
| // just do nothing if query completes | |
| query.callback = () => {} | |
| // Remove from queue | |
| var index = this.queryQueue.indexOf(query) | |
| if (index > -1) { | |
| this.queryQueue.splice(index, 1) | |
| } | |
| this._pulseQueryQueue() | |
| }, readTimeout) | |
| query.callback = (err, res) => { | |
| clearTimeout(readTimeoutTimer) | |
| queryCallback(err, res) | |
| } | |
| } |
This seems dangerous. A better solution would seem to be to issue pg_cancel_backend when client timeout is reached.
Metadata
Metadata
Assignees
Labels
No labels
Activity
rinarakaki commentedon Oct 15, 2026
A consequence worth adding: after
query_timeoutfails a query that was already sent, the client stays busy with it. So the next query waits behind it, and fails with the same timeout without ever running. Reproduced on pg 8.23.1, the latest, against Postgres 18; master (0980cef) is the same:Only after the server finishes the first query does the client answer again. So a
ROLLBACKsent after a timed-out statement in a transaction waits out its own timeout too, about twice the timeout in all.In pipeline mode, a timed-out query that was sent destroys the connection for this reason (
else if (this.pipeline)in client.js). Without pipelining it doesn't, and the client stays tied to the running query. We work around it by discarding the client once a query times out, sending nothing after it (client.release(error)), so the server ends the session.