Skip to content

Already cancelled context should not break mysqlConn #862

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

Merged
merged 2 commits into from
Oct 1, 2018

Conversation

methane
Copy link
Member

@methane methane commented Sep 28, 2018

Description

When already closed context is passed, context-aware APIs like Ping() should return error soon, and not close the connection.

Fixes #858

Checklist

  • Code compiles correctly
  • Created tests which fail without the change (if possible)
  • All tests passing
  • Extended the README / documentation, if necessary
  • Added myself / the copyright holder to the AUTHORS file

@methane
Copy link
Member Author

methane commented Sep 28, 2018

@shogo82148 Please look at this.

Don't break the connection when cancelled context is passed.

Fix go-sql-driver#858
Copy link
Contributor

@shogo82148 shogo82148 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@methane methane merged commit 361f66e into go-sql-driver:master Oct 1, 2018
@methane methane deleted the ctx-cancelled branch October 1, 2018 07:22
@arvenil
Copy link
Contributor

arvenil commented Oct 1, 2018

@methane @shogo82148 It's me again ;)
I just tested it and it doesn't work for me as expected. Now first ping = context deadline exceeded, second ping = no error 😱 and so on.
I've played with this and best results I get with this:

--- a/vendor/github.com/go-sql-driver/mysql/connection.go
+++ b/vendor/github.com/go-sql-driver/mysql/connection.go
@@ -595,10 +595,6 @@ func (mc *mysqlConn) watchCancel(ctx context.Context) error {
 		mc.cleanup()
 		return nil
 	}
-	// When ctx is already cancelled, don't watch it.
-	if err := ctx.Err(); err != nil {
-		return err
-	}
 	// When ctx is not cancellable, don't watch it.
 	if ctx.Done() == nil {
 		return nil
@@ -610,7 +606,7 @@ func (mc *mysqlConn) watchCancel(ctx context.Context) error {
 
 	mc.watching = true
 	mc.watcher <- ctx
-	return nil
+	return ctx.Err()
 }
 
 func (mc *mysqlConn) startWatcher() {

Above works perfectly.

Then however I found out another tiny issue, but maybe it is exactly that - completely different issue. When first Ping doesn't reach context timeout (so, correctly returns nil) then second Ping with timeout that he should definitely reach also returns nil. Another call and it again correctly returns context deadline exceeded. Again happens for me 100% of times.

@methane
Copy link
Member Author

methane commented Oct 1, 2018

I just tested it and it doesn't work for me as expected. Now first ping = context deadline exceeded, second ping = no error 😱 and so on.

If you are using this code, it's expected behavior.

On first Ping, db.Ping create connection before calling mysqlConn.Ping().
Timed out happend while creating connection, before mysqlConn.Ping() is called.
In this case, mysqlConn.Ping() returns the ctx.Err(), without sending any packet on the connection. It means the connection is in clean state.

On second Ping, db.Ping re-use existing connection.
Since mysqlConn.Ping() is much faster than creating connection, it success without any errors.

@arvenil
Copy link
Contributor

arvenil commented Oct 1, 2018

Yes, I think you are right. I was using different code, also with connection pool and different timings. Ok, looks good, thank you very much again and sorry for misleading comment.

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.

Subsequent call to PingContext after context timeout errors with bad connection.
3 participants