-
Notifications
You must be signed in to change notification settings - Fork 18k
database/sql: no way to protect driver.Connector.Connect(), driver.Conn.Close(), driver.Stmt.Close() from blocking #38185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
CC @kardianos |
Correct on all counts. Closing a connection is unlikely to involve a network round-trip. Or rather, I don't know of any that would require that, so I'm less worried about this. Closing a Stmt will always require a network round trip, unless the entire connection is broken. The hard thing with this is the that the sql package doesn't expose a Stmt object, just a Stmt pool object. Which makes synchronous, context bounded closing harder. Lastly, yes, the connection opener context improves the situation, but it doesn't address all the cases. I'm not 100% sure we can fix this with the current API, but you could try / make suggestions on how to best address this. Some of these issues are caused by the original API that will be hard to change unless we issue a v2. For somethings, simply better documentation, stating that drivers should include a sane timeout for certain calls would also be an improvement. |
If you don't expect Yeah, passing context to Regarding the connection opener, I thought we could pass a request bounded context from the user into |
Hi. Any update/resolution on this? |
@georgysavva I could look into updating the docs on the close. I'll also annotate the database/sql/v2 tracking issue. I'll look into the connection opener. Thanks for the ping. |
Thanks for the reply. Waiting for you feedback on connection opener. |
Change https://golang.org/cl/230438 mentions this issue: |
@georgysavva I agree that the background connection opener makes it difficult to provide a relevant context for all situations. Can you review the above CL to see if it addresses your concerns? If you have a gerrit account, please leave feedback on the CL itself, otherwise feedback here is fine too. Thanks. |
Sorry, I forgot about the third thing. Stmt.Close() shouldn't we update the docs for it as well? |
Goood point, I'll update in just a bit. |
@georgysavva I've updated and included Stmt.Close as well. (also, when merged, the CL will close this issue) |
Thanks! |
Opening a connection with Connect should still create a derived context with a timeout because some clients will not use a timeout and the connection pool may open a connection asynchronously. Likewise, if a connection close makes a network operation it should provide some type of sane timeout for the operation. Fixes golang#38185 Change-Id: I9b7ce2996c81c486170dcc84b12672a99610fa27 Reviewed-on: https://go-review.googlesource.com/c/go/+/230438 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
I was reading
database/sql
source code, looking into how it manages context when integrating with third party drivers and how context can be used to timeout operations that might block due to network failures. I think I found a few flaws:sql.DB
callsdriver.Connector.Connect(ctx)
to establish a new connection via the driver, and it does pass a context into it. One of those calls happens inside db.openNewConnection() function, but this function is a part of the background goroutine db.connectionOpener() and the context is a background context and it takes the beginning there. So the driver won't receive a request bounded context from the user (as it would receive in this call) and the user won't be able to timeout connection establishment via context and the background goroutinedb.connectionOpener()
might block in case of a network error.The driver might have an independent
connect_timeout
setting that it will use in.Connect()
to pass it tonet.Dialer.Timeout
, but it only works for the original connection dial and driver may need to exchange some system messages with the database and those read operations might block if the network is unreliable. A request bounded context with timeout set by the user would solve it. But regardless of the timeout I think it's a bit weird from the driver perspective, that sometimes it receives a background context fromsql
and sometimes it receives request bounded context from the user.My actionable here is to always pass a request bounded context from the user into
driver.Connector.Connect(ctx)
.sql.DB
callsdriver.Conn.Close()
to signal the driver to close the connection, this call might include network operation and in case of a failure will block the caller, some places theresql
calls.Close()
:here, and here. If the first call blocks, it will block the background goroutine
db.connectionOpener()
, if the second call blocks, it will block the main user goroutine. Another affected place is .closeDBLocked function: it sequentially closes all connections in the pool ondb.Close()
and if one of thoseConn.Close()
blocks, it won't be able to close other connections in the pool.I think it would be better to close driver connection asynchronously (in a separate gorutine) with a reasonable, default timeout: e.g. 5 seconds. Or the original idea of the
sql
library, that driver itself must ensure thatConn.Close()
doesn't block?driver.Stmt.Close()
:sql
doesn't pass context into it and calls it in a lot of places, the most obvious here. DriverStmt.Close()
call most likely will involves network operations that might block and it will hang the main user goroutine.I think
sql
should pass a request bounded context from the user intoStmt.Close()
, becauseStmt.Close
is a user facing operation and user should be able to timeout it.Please let me know If I missing something.
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputThe text was updated successfully, but these errors were encountered: