Skip to content

Conversation

@ntninja
Copy link

@ntninja ntninja commented Feb 9, 2026

Reconnects to PostgreSQL when receiving BrokenPipe upon executing freestandig query or transaction start.

In-transaction queries are not retried, since we’d have to replay all previous queries and still risk inconsistency if a subsequently issued queries depended on data previously read during the aborted transaction. (We’d also have to keep a log of all previously returned data to verify that it hasn’t changed when reissuing the command!)
This patchset does convert BrokenPipe to TransactionError to let applications know that they should restart the transaction: If the database is really down, the subsequent .begin() will then fail with a ConnectionError.

This allow removes the calls to .commit() in the transaction error handling, see last commit message for why and why this doesn’t actually change application observable behaviour.

Fixes #436

…ng transaction command

Automatically reconnecting for an in-transaction queries is not supported, as we’d have to replay all previous queries and still risk inconsistency if any subsequently issued application queries depended on data previously read during the disconnected transaction.

We’d *also* have to keep a log of all previously returned data to verify that it hasn’t changed when reissuing the command – an unacceptable overhead, particularly since applications must be able to handle transaction conflicts anyway and this patch just makes disconnects look like any other “please retry transaction” condition.
Committing partial transactions is a great way to induce data corruption by committing inconsistent data to the database. Transaction MUST always form a unit!

Fortunately, this probably never mattered in practice as PostgreSQL will put transactions with failed commands into an *aborted* state, where the only valid subsequent in-transaction command is rolling back partially or completely:

> […] Moreover, ROLLBACK TO is the only way to regain control of a transaction block that was put in aborted state by the system due to an error, short of rolling it back completely and starting again.

https://www.postgresql.org/docs/current/tutorial-transactions.html

So this “only” improves error messages and avoids an unnecessary round trip, not change application observable behaviour.
@ntninja
Copy link
Author

ntninja commented Feb 9, 2026

This can be manually tested:

  1. Start up some Deno application using Pool, making sure it connects to the database
  2. Run ps aux | grep postgres to list all PostgreSQL instances
  3. Run kill <pids, …> to with the process IDs of all PostgreSQL instances serving the started application
  4. Perform some database-dependant task in the application and observe new PostgreSQL instance being started, rather than the application crashing with Deno.errors.BrokenPipe.

This applies to bewCloud, for instance.

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.

BrokenPipe: Broken pipe (os error 32) not handled in reconnect logic

1 participant