Handle QueryInterrupted exceptions when canceling completed queries.#248
Conversation
KILL QUERY will interrupt a subsequent query if the command it was intended to cancel has already completed, and the connection is idle. In order to handle this case, we issue a dummy query to catch the QueryInterrupted exception. See https://bugs.mysql.com/bug.php?id=45679.
| // KILL QUERY will kill a subsequent query if the command it was intended to cancel has already completed. | ||
| // In order to handle this case, we issue a dummy query to catch the QueryInterrupted exception. | ||
| // See https://bugs.mysql.com/bug.php?id=45679 | ||
| var killClearCommand = new MySqlCommand("SELECT * FROM fake_table LIMIT 0;", connection); |
There was a problem hiding this comment.
Did you try something like DO SLEEP(0.001) to clear the pending cancellation?
There was a problem hiding this comment.
DO SLEEP(0) is even better (for some reason I was assuming it had to be a non-zero wait, but SLEEP(0) seems to work fine).
| killCommand.CommandTimeout = 3; | ||
| killCommand.ExecuteNonQuery(); | ||
|
|
||
| commandToCancel.IsCanceled = true; |
There was a problem hiding this comment.
I think this IsCanceled property should be combined with the existing MySqlSession.m_state so that all state related to cancellation is in one place.
There was a problem hiding this comment.
I want to handle this situation in MySqlSession.FinishQuerying; I can push that change.
There was a problem hiding this comment.
I started messing around with the states, but if you know how you want to tackle this I have Allow edits from maintainers turned on, so go for it.
| } | ||
|
|
||
| [Fact] | ||
| public async Task CancelCompletedCommand() |
There was a problem hiding this comment.
I'm not getting any kind of failure from this test when running it without the new code (so it's difficult to verify that the problem is fixed).
There was a problem hiding this comment.
What version of MySQL are you testing with? I tested this on 5.6.29. According to a duplicate of the bug I linked, the issue may be
repeatable with server version 5.1/5.5/5.6 and NOT REPEATABLE with server version 5.0 and 5.7
There was a problem hiding this comment.
I was using 5.7.
I still can't repro a failure with this test with 5.6, although I can get an unhandled exception when using Dapper's Query<int> followed by Execute.
|
|
||
| using (await cmd.ExecuteReaderAsync().ConfigureAwait(false)) | ||
| cmd.Cancel(); | ||
| } |
There was a problem hiding this comment.
Does this need to be followed by a second command that will be the unintentional victim of cancellation?
There was a problem hiding this comment.
The Dispose method should be executing the second command, but perhaps it would be better to be explicit.
There was a problem hiding this comment.
I tried SELECT 2; but that doesn't repro the problem, as per bullet 2 of bug 45679. So I think the INSERT/UPDATE combination of commands is a good one.
Handle QueryInterrupted exceptions when canceling completed queries.
KILL QUERY will interrupt a subsequent query if the command it was intended to cancel has already completed, and the connection is idle. In order to handle this case, we issue a dummy query to catch the QueryInterrupted exception. See https://bugs.mysql.com/bug.php?id=45679.
I ran into this issue while using Dapper's
QueryImplmethod. Ifreader.FieldCount == 0, then Dapper will try to cancel the query. Upon the next command issued by the connection, it is immediately interrupted.Generally, using
Querywithout selecting any columns is wrong, but this would be a problem for any query that completed before it was canceled. The MySQL.Data implementation from Oracle handles both of these cases without an error.