-
Notifications
You must be signed in to change notification settings - Fork 333
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
Implement CommandTimeout #67
Comments
I have a WIP of this here: caleblloyd@d061332 Commands are properly timing out, but the next command that goes over the same connection hits issues with reading packets out of order. Should the default logic be to reset a connection that hits a command timeout? |
This is potentially going to be complicated.
|
MariaDB/J opens another connection to run the You're correct in #3, load balanced connections could come into play here. If it's round-robin DNS balanced connections, we could store the resolved IP Address of the server in the Connection. If it's Layer 4 load balancing, there's no way to guarantee you get the same server (some router with a consistent IP address is maintaining a NAT Table to a cluster of MySQL servers). If the driver has to open another connection anyways, why not just dispose the timed-out socket first, and replace it with a fresh socket? As long as MySQL internally cleans up the transaction on a disposed socket, this approach should work. This approach could be implemented in |
This would lose all session variables, temporary tables, etc. If the client is able to keep using the same I'm thinking that the connection pool should have n dedicated |
MySql.Data does implement
I like the idea of saving the IP Address of the server that was connected to in the Session and trying to reconnect to this specific server. I think this should be a one-off connection outside of the pool when
Does the Server ID get sent from the server when opening a connection? If so we should save this in the Session also. As a last resort, if we can't open a new connection to the server (server connection limit hit or server went down without a clean shutdown), or server IDs do not match (layer 4 load balancing) should we dispose the socket and switch it out with a new one? Would this require a different exception message? |
Sounds good.
Not sure what you mean by "Server ID". There is a server version and a (server-local) connection ID in the initial handshake packet. AFAIK there's no value that uniquely identifies a server.
I think it would be best to throw a |
The server_id global variable is used in replicated setups. It is required to be unique for replication to start, but looks like it's not sent in the initial handshake packet. There is a "Replication" option that can be set in the connection string. If this was set, we could run a The worry is that without comparing |
The |
While this is not supported, what is the current behavior? It just runs forever? |
Yes, it will run until the server returns results.
|
Interestingly,
What I dislike about it is that it will add some (probably non-trivial) amount of overhead to track the remaining time allotted to each method call and set a timer that will call
|
MySql.Data has an interesting feature where it kills the query, silently swallows any results returned by it (so the connection/session is still in a valid state), then throws the timeout exception. This may be interesting to implement. |
That's fine for me. I just migrated my entire cluster to MySqlConnector and EFCore now, so I had to remove the "Default Command Timeout" overrides from connection strings. I have a lot of queries that take 10 minutes or more to complete, and in all cases, I was adding more time, guess I never thought about not having them at all. Didn't know about async not using them. For now I'll just take that into account and move to cancellation tokens where necessary. Thanks! |
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
👍
I'm working on a patch that will accept this connection string setting.
You could set
To clarify, that was the Microsoft SQL Client documentation. I haven't checked the code but I would assume that MySql.Data does use |
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
hey what is the solution, can we download the dev repo and change the timeout1? i tried using ado .net too but even that too defaults too 30 seconds |
Not really, because it's not implemented yet. (Right now, you shouldn't be observing any timeouts happening, because there's no code in place to make them happen.) |
I have been noticing some queries running forever here, no idea why. It seems having the timeout could act like a failsafe for these queries so at least I can notice them. I've tested adding a timeout with a CancellationToken, but I noticed that it doesn't fail with an exception when the token is cancelled. This causes the fail to be silent. I tried to handle this manually with something like this:
But the throw must be inside the command executor or even deeper in the datareader, otherwise the token might be cancelled after the query finishes but before testing for the token. Also, using the token has the downside of not being able to use Dapper to set the timeout like: |
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
DefaultCommandTimeout is set to 0 (i.e., no timeout) instead of 30 as in MySql.Data. This should remove unnecessary performance overhead of setting a timer for every single operation. This library also starts the timer from the beginning of the public method call, instead of the cumulative total of network I/O time.
I've realised that most of my earlier analysis is incorrect. There are two important types of cancellation: logical and physical. The logical cancellation (triggered by passing a
|
Implemented in 0.29.0. |
Dear Bradley, Kindly please clarify what exactly happens when Command is timed out? Assuming that we are executing heavy UPDATE on some of MySQL table. Whether MySQL command will succeed from the MySQL point of view? What exactly happenned in connector on timeout detection? Whether KILL QUERY will be send to MySQL? (and, if I'm understanding correctly, this can potentially lead to data corruption) Thank you in advance. |
The client will abort the connection. I don't know if this means a TCP RST packet is sent or not; you could look with Wireshark to find out.
I don't think the server behaviour is precisely defined in this situation. It might even depend on the exact version of MySQL Server you're using, or whether you're using MySQL Server or MariaDB or another MySQL variant.
No, this will not happen with command timeout. Command Timeout exists to prevent the client from hanging if the server becomes unreachable, so it aborts the current connection instead of executing more server commands. (If you do want
I haven't heard about this, but I haven't done a lot of reading about how
This seems possible, but I have never tested it to see. Again, consult your MySQL Server manual to see if its behaviour is documented. |
Ok, thank you for your response. |
hi @bgrainger , we are encountering the same issue with this library, the query keeps on running in the server while in the client side, it has been time out already (since we set the DEFAULT COMMAND TIMEOUT in the connection string to just 10 seconds). Basically we also want to cancel and cut very long running queries based on the timeout that we set and it should be reflected in the server side as well. How can we implement this in this library? |
for this i've used set max session timeout, or the query level equivalent. @bgrainger It would be good to have an easier way to handle timeouts (or some documentation). |
@CatalinAdlerDF i agree with you. I hope this can be set in the Code level (per connection) something like Connection.MaxExecutionTime = 8000; (in milliseconds) or something similar that will indicate the library to make either auto cancel or kill the query when the timeout reaches. This will be a very good and critical feature. We are doing default command timeouts and with retry functionality, when the retry triggered, there will be so many additional queries that is running in the DB and causing our entire DB server to slowdown and eventually crash and unusable. We have just noticed this behaviour today and caused our entire production platform to down. We are using the Default Command Timeout for the purpose of avoiding running very long queries in the production. In real application, this feature is a must and critical. I really hope that this can be implemented in this library, this is a critical feature in a production @bgrainger |
But it is implemented, and it actually sends a kill command to mysql on a different connection. My point was just to try to make it simpler, if possible. btw, just a thought, all operations in a prod app need a correctly enforced timeout; otherwise the system will never be controllable. |
@CatalinAdlerDF how did you implement the "it actually sends a kill command to mysql on a different connection" ? Please help me. The only option i know is setting a /*+ MAX_EXECUTION_TIME({0}) */ in a query but we have tons of sql queries in our data layer and doing this needs to modify each every query that we have in our code which is not a fast solution. |
That is currently done by explicitly calling #455 is open to track improving this. npgsql just made a similar change (npgsql/npgsql#1567) so there may be lessons from their work this project can adopt. |
@bgrainger not all our data layer is using the async versions, for the sync version, we tried calling MySqlCommand.Cancel in the catch exception part however upon calling it, we received another InvalidOperationException: Connection must be Open; current state is Closed. Our code: using (myCommand)
How can we force kill the running query upon timeout in the sync version? I am using the 0.65 version from nuget |
for our async version, we tried applying cancellationToken source for timeout, however, how can we determine if the task was successful or reached the timeout? Here is our code: var cancelToken = new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token;
I am using the 0.65 version from nuget |
@firephantomassasin If you execute select sql queries you can use the mysql server support for execution timeouts: session or statement level. |
@CatalinAdlerDF yes that's what i'm implementing. But i want to implement in the library as well such as MySqlCommand.Cancel, however it is throwing some errors. Hi @bgrainger please help on how to use the MySqlCommand.Cancel when timeout error occurred |
@firephantomassasin Can't you use the overloads that take in a CancellationToken? |
There is now a proposal to implement this: #455 (comment) |
1. Implement
DefaultCommandTimeout
in the connection stringConnection String Documentation
2. Implement
CommandTimeout
inMySqlCommand
MySqlCommand Documentation:
Implementation Notes:
It sounds like Oracle's implementation of
CommandTimeout
is setting Socket.SendTimeout and Socket.ReceiveTimeout. They start at the timeout value (e.g. 30 seconds) and subtract only time spent in I/O. This becomes the send or receive timeout for the next socket command.The text was updated successfully, but these errors were encountered: