Gracefully terminate long running SQL Server query from ADO.NET - c#

I use an asynchronous process to retrieve data from a long running SQL query. The process calls a stored procedure through the SqlCommand.BeginExecuteReader() method.
At times, I would like to shut my process down and gracefully terminate any running queries.
After some testing, it seems as if calling SqlConnection.Close() is sufficient. For good measure, I also explicitly call SqlConnection.Dispose().
When running a trace through SQL Server Profiler, it appears as if the query is ended gracefully as I see a SQL:BatchStarting followed by a SQL:BatchCompleted after calling Close().
Can anyone please confirm whether closing the connection is all that is required?

Calling Close is sufficient, just a few remarks:
First of all make sure you write your Close methods inside finally block to ensure correct exception handling.
Also you do not need to call both SqlConnection.Close and SqlConnection.Dispose methods as they both do the same. Dispose method is added to implement IDisposable pattern and this method internally calls SqlConnection.Close method, which has more natural name, because we close connections, but not dispose them :)
If you are using DataReader then you have to close it as well each time after you want to use connection for other purpose.

Related

Does "await command.ExecuteReaderAsync()" wait for the query to finish before returning?

I'm confused about the behavior of this command:
SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess)
I would ideally like to start the query running and as soon as SQL server starts returning results, start processing them. This is as opposed to waiting for all results to be returned by SQL Server. It appears like this could speed up my program by about 40% given when SQL Server Management Studio starts returning results for my query.
It appears that it should be possible and some places such as this seem to indicate that it is.
I'm new to async programming, however, it seems to me like that command is calling the reader, spinning off a separate thread to do it, then waiting for the ExecuteReader to finish, which then returns a finished SQLDataReader.
Meaning that command is exactly equivalent to this without async:
SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess)
Or does the SQLDataReader returned from ExecuteReader naturally support streaming and only wait long enough for the stream to be available before returning? Does it work whether or not I call ExecuteReader vs ExecuteReaderAsync?
Thanks in advance!
however, it seems to me like that command is calling the reader, spinning off a separate thread to do it, then waiting for the ExecuteReader to finish, which then returns a finished SQLDataReader.
You are wrong. What async methods are supposed to do is start an operation, "pause" the execution of current method, freeing up the current thread, and, after the operation becomes available, restore the state machine and call the rest of method.
Connecting to SQL server is an I/O operation, which should be run in asynchronous mode, because you don't really need a .Net thread for this operation. After connection is open, both synchronous and asynchronous reader will behave exactly the same - as normal .Net classes.
Comparing to synchronous version of this method you'll got one free thread at a time of connecting to the SQL server and a small overhead for a state machine.

C# Move operation hangs instead of throwing exception immediately

Does anyone know why sometimes a Directory.Move() operation in C# hangs/waits instead of throwing an exception immediately?
For example:
If I use the Directory.Move() method inside a try block, then navigate to that folder in File Explorer, Windows creates some handles locking it.
Then, I expect the catch block to be executed immediately, but instead it's like the application just hangs for 10-15 seconds before it throws an exception.
The funny thing is, that if I go outside of the folder in File Explorer during these 10-15 seconds, then the application actually completes the Move() operation.
It's like: instead of throwing an exception immediately, Windows hangs for 10-15 seconds to see if the people who are responsible for the handles (locks) closes these handles by themselves.
Is there a way to make the application throw the exception immediately?
The answer to your question "Does anyone know why sometimes a move operation in C# hangs/waits instead of throwing an exception immediately?" is probably that the .net framework is issued with a Pending state from its request for an NTFS lock, and eventually gives up.
The System.IO.Directory.Move maps directly to a Kernel32 function; I guess that eventually this finds itself calling LockFileEx (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx) which allows the caller to specify whether to immediately fail if the lock cannot be obtained, or wait for a specified time. I guess that Kernel32 uses the variant of this which allows for the setting of a timeout. It doesn't seem that the .net framework has any influence on what timeout it used.

C# Thread.Abort() + ODBC Connection

What happens if I call Thread.Abort() (in C#/.NET) on a thread that is currently executing an ODBC Command (specifically against MSSQL and Oracle, but also generally)? Will the command get cancelled? Will the DB server recognize there's nothing at the other end of the connection and kill the process (again, specifically MSSQL and Oracle)? Or do I need to explicitly call Cancel() on the connection first?
My goal is to ensure the safety of the database I'm connecting to if the worst should happen to my application (or the worst that I can catch and respond to, like system shutdowns etc).
I'd like to program defensively and try to issue a Cancel() if at all possible, but I'd like to know the behavior anyway.
If you want to ensure cancelling the SQL command, why not to use the TransactionScope.Dispose() method or simply do not Complete the transaction? It works above Thread, Process and such abstractions, and there will be no races between Thread cancelling and SQL command.
Also, as was stated in comments, your SQL driver can work in other Thread and can even be an unmanaged code, so the cancelling the Thread will not affect the SQL command, and you really need to Cancel() your connection or command.

Multithreaded database access

On my c# project, i have an SQL connection in MARS mode that is being used by multiple threads to perform CRUD operations. Some of these operations are required to be performed as a transaction. After i completed the data access module, i started testing and got an InvalidOperationException from one of the selects, stating that since the connection had an active transaction, the select itself needed to be in a transaction. Snooping around MSDN i found the following remark:
Caution: When your query returns a large amount of data and calls BeginTransaction, a SqlException is thrown because SQL Server does not allow parallel transactions when using MARS. To avoid this problem, always associate a transaction with the command, the connection, or both before any readers are open.
I could easily create a method that would aggregate commands into a transaction, this would even allow me to have a timer thread committing transactions on a regular interval, but is this the right way? Should i instead halt commands that don't need a transaction until an active transaction is committed?
I would stay away from MARS.
See:
used by multiple threads to perform CRUD operations
That screams "every thread one connection, and it's own transaction" unless you have a very rare case here. This absolutely does not sound like a valid use case for MARS.

A reasonable use of threading in C#?

As part of a large automation process, we are calling a third-party API that does some work calling services on another machine. We discovered recently that every so often when the other machine is unavailable, the API call will spin away sometimes up to 40 minutes while attempting to connect to the remote server.
The API we're using doesn't offer a way to specify a timeout and we don't want our program waiting around for that long, so I thought threads would be a nice way to enforce the timeout. The resulting code looks something like:
Thread _thread = new Thread(_caller.CallServices());
_thread.Start();
_thread.Join(timeout);
if (_thread.IsAlive)
{
_thread.Abort();
throw new Exception("Timed-out attempting to connect.");
}
Basically, I want to let APICall() run, but if it is still going after timeout has elapsed, assume it is going to fail, kill it and move on.
Since I'm new to threading in C# and on the .net runtime I thought I'd ask two related questions:
Is there a better/more appropriate mechanism in the .net libraries for what I'm trying to do, and have I committed any threading gotchas in that bit of code?
Thread.Abort() is a request for the thread to abort, and gives no guarantee that it will do so in a timely manner. It is also considered bad practice (it will throw a thread abort exception in the aborted thread, but it seems like the 3rd party API offers you no other choices.
If you know (programmatically) the address of the remote service host you should ping it before you transfer control to the 3rd party API.
If not using a backgroundworker, you could set the thread's IsBackgroundThread to true, so it doesn't keep your program from terminating.
Bad idea. Thread.Abort doesn't necessarily clean up the mess left by such an interrupted API call.
If the call is expensive, consider writing a separate .exe that makes the call, and pass the arguments to/from it using the command line or temporary files. You can kill an .exe much more safely than killing a thread.
You can also just use a delegate... Create a delegate for the method that does the work, Then call BeginInvoke on the delegate, passing it the arguments, and a callback function to handle the return values (if you want)...
Immediately after the BeginInvoke you can wait a designated time for the asynch delegate to finish, and if it does not in that specified time, move on...
public delegate [ReturnType] CallerServiceDelegate
([parameter list for_caller.CallService]);
CallerServiceDelegate callSvcDel = _caller.CallService;
DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds);
IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters],
AsynchCallback, null);
while (!aR.IsCompleted && DateTime.Now < cutoffDate)
Thread.Sleep(500);
if (aR.IsCompleted)
{
ReturnType returnValue = callSvcDel.EndInvoke(aR);
// whatever else you need to do to handle success
}
else
{
callSvcDel.EndInvoke(aR);
// whatever you need to do to handle timeout
}
NOTE: as written AsynchCallback could be null, as the code retrieves the return value from the EndInvoke(), but if you want to you can have the CallService() method call the AsynchCallback delegate and pass it the return values instaed...
It might work, but nobody could say for sure without an understanding of the third-party API. Aborting the thread like that could leave the component in some invalid state that it might not be able to recover from, or maybe it won't free resources that it allocated (think - what if one of your routines just stopped executing half-way through. Could you make any guarantees about the state your program would be in?).
As Cicil suggested, it might be a good idea to ping the server first.
Does your application run for long periods of time or is it more of a run-as-needed application? If it's the latter, I personally would consider using the Thread.Abort() option. While it may not be the most desirable from a purist's perspective (resource management, etc.), it is certainly straightforward to implement and may foot the bill given the way your particular application works.
The idea of a separate executable makes sense. Perhaps another option would be to use AppDomains. I'm not an expert in this area (I welcome refinements/corrections to this), but as I understand it, you'd put the API call in a separate DLL and load it into a separate AppDomain. When the API call is finished or you have to abort it, you can unload the AppDomain along with the DLL. This may have the added benefit of cleaning up resources that a straightforward Thread.Abort() will not.

Categories

Resources