Skip to content

Conversation

@ftonato
Copy link

@ftonato ftonato commented Jan 5, 2026

Problem

When a query fails with ECONNRESET (or any connection error), calling pg.end() hangs forever. This happens because:

  1. When a connection error occurs, the query variable in the connection is never cleared
  2. In the normal path, ReadyForQuery clears query = null, but connection errors never reach that handler
  3. When end() is called, it checks !query to determine if it can terminate immediately
  4. Since query still references the rejected query object, the condition fails and end() creates a promise waiting for ended to be called
  5. However, ended is only called in terminate(), which is only called when !query is true - creating a deadlock

Solution

I've made two changes to ensure the query variable is properly cleared when connection errors occur:

  1. In errored() function: Clear query = null after rejecting the query
  2. In closed() function: When hadError is true, clear the query before closing (since errored() might not always be called in all error paths)

Changes

  • src/connection.js:
    • Modified errored() to clear query after queryError()
    • Modified closed() to clear query when hadError is true
  • tests/index.js: Added test 'end() completes after ECONNRESET error' to verify the fix

Testing

The new test creates a real PostgreSQL connection, terminates the backend during a query execution, and verifies that end() completes quickly (within 1 second) instead of hanging forever.

Notes

I'm not entirely sure if this is the best approach - I spent a significant amount of time understanding the codebase and the problem. The connection lifecycle and query state management is quite complex, and I wanted to make sure I understood the flow before making changes. I also received help from AI to better understand the problem and explore the codebase, which was invaluable in identifying where the query variable needed to be cleared.

I'm open to feedback and alternative approaches if there's a better way to handle this!

Fixes #1130

- Clear query variable in errored() after rejecting query
- Clear query variable in closed() when hadError is true
- Add test to verify end() completes after connection errors

Fixes porsager#1130
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: If a query fails, it never ends

1 participant