-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Subsequent call to PingContext
after context timeout errors with bad connection
.
#858
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
I've only tested this on |
If timeout happened before sending any packets, it's safe. |
Can I have your Go version? I implemented SessionResetter #779 , |
$ go version
go version go1.10.3 darwin/amd64 |
@methane @shogo82148 Could you try to run example code and post results here? Would be really useful to me if you could confirm the behavior. package main
import (
"context"
"database/sql"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "root@/")
if err != nil {
panic(err)
}
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
for {
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, time.Millisecond)
err := db.PingContext(ctx)
if err != nil {
log.Println(err)
}
cancel()
time.Sleep(time.Second)
}
} |
@shogo82148 Lines 602 to 606 in 99ff426
Note that On next Ping, Lines 591 to 597 in 99ff426
After mc.watchCancel() returned, Ping calls Since the error happened before sending any data, How do you think about moving --- a/connection.go
+++ b/connection.go
@@ -599,7 +607,6 @@ func (mc *mysqlConn) watchCancel(ctx context.Context) error {
return nil
}
- mc.watching = true
select {
default:
case <-ctx.Done():
@@ -609,6 +616,7 @@ func (mc *mysqlConn) watchCancel(ctx context.Context) error {
return nil
}
+ mc.watching = true
mc.watcher <- ctx
return nil |
Don't break the connection when cancelled context is passed. Fix go-sql-driver#858
Don't break the connection when cancelled context is passed. Fix go-sql-driver#858
Issue description
After first call to
PingContext
quits withcontext deadline exceeded
the subsequent call will returnbad connection
.With plenty of debug lines I've tracked down the issue a bit. Firstly, timing is really important here and e.g. with
time.Millisecond
I hit the error but withtime.Nanosecond
each call correctly returnscontext deadline exceeded
. So please be aware that you may need to adjust those values to be able to reproduce the issue.When I used
time.Nanosecond
thecontext deadline exceeded
is returned by sql package before connection is taken from the pool https://github.com/golang/go/blob/ce58a39fca067a19c505220c0c907ccf32793427/src/database/sql/sql.go#L1086-L1091However with
time.Millisecond
, it has enough time to pass those checks and timeout is reached in this librarymysql/connection.go
Lines 603 to 606 in 99ff426
As of now, the
context deadline exceeded
error is returned and connection is returned to the pool.Second call to
PingContext
now picks up the previously used connection and tries to send data but fails and returnsmysql/packets.go
Line 142 in 99ff426
I've tracked it a bit, but I'm still not sure about the reason. I was able to "fix" the issue by adding
mc.cleanup()
before returningcontext deadline exceeded
.However this leads to two calls to
DB.conn()
instead of one as this bad connection was left in the pool https://github.com/golang/go/blob/ce58a39fca067a19c505220c0c907ccf32793427/src/database/sql/sql.go#L730-L731Another hack I've tried was to return
driver.ErrBadConn
insteadcontext deadline exceeded
. This takes out the connection out of the pool (ctx timeout doesn't remove connection from the pool) but we loose information about the real error.And of course this raises a question - if context timeouts should we assume we can't re-use that connection anymore?
Example code
Error log
The text was updated successfully, but these errors were encountered: