Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
npgsql leaving connections open on IOExceptions #2288
Steps to reproduce
Please see the https://github.com/codeweaversdev/npgsql-transaction-error-handling repo for a demonstation application
Commands that take longer than the command timeout to finish execution throw a System.IO.IOException because the connected party (pg) did not properly respond after a period of time.
This leaves an active process in PG:
When handling the thrown exception, there is no way to test the state of the transaction/command as the
If you transaction.RollBack() in a finally then an InvalidOperationException is thrown.
In our actual use-case we are seeing UPDATE statements that perform bulk changes timeout, leaving the transaction hanging on production and requiring manual intervention from the DBA to resolve by using
We would expect that we are able to rollback the transaction from the application in this scenario and npgsql honours the behaviour of the
Further technical details
Npgsql version: 4.0.4
The physical connection should definitely not be left open in case of a timeout - I'll try to investigate that soon.
Regarding rolling back and ascertaining transaction state... When a socket timeout occurs, the physical connection is assumed to be in an unusable state, since protocol sync has been lost. The (current) expected behavior is therefore for the connection to be closed (broken) as soon as a timeout occurs. In other words, after a timeout occurs it no longer makes sense to send a rollback, because there's no longer a connection to roll back on. As a general rule, this also means that the transaction is automatically rolled back on the PostgreSQL side as the connection is closed without a commit. So assuming we're doing things right, when a timeout exception occurs one can assume that the transaction failed and was rolled back. One exception for this is if the timeout occurs during the commit itself, in which case there's no way of knowing whether the commit succeeded or failed.
Note that in addition to the default socket timeout, PostgreSQL also supports a
After a 2nd look this is the current expected behavior, although we may implement #1567 to improve this. It's worth reading that issue and the issues it references to fully understand what's going on. Note that this is very different from PostgreSQL timeouts which can be set via
Regarding the socket timeout issue, in a nutshell, when a socket timeout occurs, network connectivity is assumed to be severed and Npgsql closes the connection on its side. On the PostgreSQL side the current query continues to execute until it is completed - PostgreSQL doesn't check the state of the network connection with the client while it's executing a statement (unless it needs to write back results). #1567 would be about attempting to establish a new, separate connection in order to cancel the running statement - this obviously would work only if there's no actual network issue.
Note also #1606 which is about attempting cancellation of all connections on process exit.
If anything about this is unclear please feel free to write back.