I have the following code where I'm trying to make a request to a remote endpoint using HttpClient:
using (var client = new HttpClient())
{
client.BaseAddress = _serviceBaseAddress;
Task<HttpResponseMessage> readResponseTask = client.GetAsync(relativeUri);
readResponseTask.Wait();
using (var response = readResponseTask.Result)
{
if (response.StatusCode == HttpStatusCode.NotFound || !response.IsSuccessStatusCode)
{
return default(TResult);
}
Task<TResult> readContentTask = response.Content.ReadAsAsync<TResult>();
readContentTask.Wait();
TResult value = readContentTask.Result;
return value;
}
}
..and occassionally I would get ThreadAbortException at the readResponseTask.Result like so:
System.Threading.ThreadAbortException: Thread was being aborted. at
System.Threading.Monitor.ObjWait(Boolean exitContext, Int32
millisecondsTimeout, Object obj) at
System.Threading.ManualResetEventSlim.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.SpinThenBlockingWait(Int32
millisecondsTimeout, CancellationToken cancellationToken) at
System.Threading.Tasks.Task.InternalWait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken)
Under what circumstance will the .Result throw such an exception? I have tried simulating a timeout on the remote endpoint but I got the exception at the .Wait() instead of .Result. Since the exception happens after .Wait(), I'm assuming the result has already been returned from the remote site but somehow something went wrong when it tries to access the result.
Any clues? Could it be something to do with thread concurrency?
I would get ThreadAbortException at the readResponseTask.Result
No, you don't. The call stack clearly shows that it is in fact the Wait() call that produced the exception. Note the frequent appearance of the word "wait" in the trace.
Hard to see how you got confused. Keep in mind that the Task.Result property getter is very small and is going to be inlined when you run the Release build of your program. So you never can see it back in the stack trace.
Perhaps you'll be ahead by simply removing the Wait() call. It isn't necessary, the Result property getter already performs a wait if necessary.
During Wait(), the thread is aborted from outside. Nobody can tell for sure why.
Enabling network client trace can help detecting the root cause.
First, do not use .*Async() if you're going to immediately call .Wait(). This is poor practice and will more than likely lead to errant results. Instead use the synchronous versions of the calls, client.Get(relativeUri) and the following:
TResult value = response.Content.ReadAs<TResult>();
return value;
If you intend on not taking advantage of the .NET frameworks asynchronous programming model.
But if you would rather take advantage of the asynchronous I/O capabilities, you should do so following the best practices. Use the async/await keywords and make your methods look as though they are synchronous while leveraging the capabilities of the .NET framework's asynchronous keywords.
I can only imagine the entry point to your method looks something like this:
public TResult InvokeClientGet<TResult>(string relativeUri)
{
// ... left out for brevity
}
This is actually preventing you from using the async/await keywords. Instead try the following:
public async Task<TResult> InvokeClientGet<TResult>(string relativeUri)
{
try
{
using (var client = new HttpClient { BaseAddress = _serviceBaseAddress })
{
using (var response = await client.GetAsync(relativeUri))
{
if (response.StatusCode == HttpStatusCode.NotFound ||
!response.IsSuccessStatusCode)
{
return default(TResult);
}
return await response.Content.ReadAsAsync<TResult>();
}
}
catch (Exception ex)
{
// Handle exceptional conditions
}
}
A few words specifically about System.Threading.ThreadAbortException.
When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before ending the thread. Because the thread can do an unbounded computation in the finally blocks or call Thread.ResetAbort to cancel the abort, there is no guarantee that the thread will ever end. If you want to wait until the aborted thread has ended, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually stops executing.
With that being said, if something is calling .Abort() and causing this exception. There isn't much you can do to prevent it. Regardless, try following best practices.
I had the same problem while testing a method via Unit-Tests which was sending Data to a WebService. (ik there are better ways to do that)
The problem was that the Unit-Test called my async method but didn't waited unitl the WebService call had finished. This aborted the WebService call and i got an ThreadAbortException.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
bs.CallWebService();
}
All I needed to do was to make the Unit-Test wait until the WebService call has finished by adding the keyword await.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
var result = await bs.CallWebService();
Assert.NotNull(result);
}
Related
We have a third-party method Foo which sometimes runs in a deadlock for unknown reasons.
We are executing an single-threaded tcp-server and call this method every 30 seconds to check that the external system is available.
To mitigate the problem with the deadlock in the third party code we put the ping-call in a Task.Run to so that the server does not deadlock.
Like
async Task<bool> WrappedFoo()
{
var timeout = 10000;
var task = Task.Run(() => ThirdPartyCode.Foo());
var delay = Task.Delay(timeout);
if (delay == await Task.WhenAny(delay, task ))
{
return false;
}
else
{
return await task ;
}
}
But this (in our opinion) has the potential to starve the application of free threads. Since if one call to ThirdPartyCode.Foo deadlock the thread will never recover from this deadlock and if this happens often enough we might run out of resources.
Is there a general approach how one should handle deadlocking third-party code?
A CancellationToken won't work because the third-party-api does not provide any cancellation options.
Update:
The method at hand is from the SAPNCO.dll provided by SAP to establish and test rfc-connections to a sap-system, therefore the method is not a simple network-ping. I renamed the method in the question to avoid further misunderstandings
Is there a general approach how one should handle deadlocking third-party code?
Yes, but it's not easy or simple.
The problem with misbehaving code is that it can not only leak resources (e.g., threads), but it can also indefinitely hold onto important resources (e.g., some internal "handle" or "lock").
The only way to forcefully reclaim threads and other resources is to end the process. The OS is used to cleaning up misbehaving processes and is very good at it. So, the solution here is to start a child process to do the API call. Your main application can communicate with its child process by redirected stdin/stdout, and if the child process ever times out, the main application can terminate it and restart it.
This is, unfortunately, the only reliable way to cancel uncancelable code.
Cancelling a task is a collaborative operation in that you pass a CancellationToken to the desired method and externally you use CancellationTokenSource.Cancel:
public void Caller()
{
try
{
CancellationTokenSource cts=new CancellationTokenSource();
Task longRunning= Task.Run(()=>CancellableThirdParty(cts.Token),cts.Token);
Thread.Sleep(3000); //or condition /signal
cts.Cancel();
}catch(OperationCancelledException ex)
{
//treat somehow
}
}
public void CancellableThirdParty(CancellationToken token)
{
while(true)
{
// token.ThrowIfCancellationRequested() -- if you don't treat the cancellation here
if(token.IsCancellationRequested)
{
// code to treat the cancellation signal
//throw new OperationCancelledException($"[Reason]");
}
}
}
As you can see in the code above , in order to cancel an ongoing task , the method running inside it must be structured around the CancellationToken.IsCancellationRequested flag or simply CancellationToken.ThrowIfCancellationRequested method ,
so that the caller just issues the CancellationTokenSource.Cancel.
Unfortunately if the third party code is not designed around CancellationToken ( it does not accept a CancellationToken parameter ), then there is not much you can do.
Your code isn't cancelling the blocked operation. Use a CancellationTokenSource and pass a cancellation token to Task.Run instead :
var cts=new CancellationTokenSource(timeout);
try
{
await Task.Run(() => ThirdPartyCode.Ping(),cts.Token);
return true;
}
catch(TaskCancelledException)
{
return false;
}
It's quite possible that blocking is caused due to networking or DNS issues, not actual deadlock.
That still wastes a thread waiting for a network operation to complete. You could use .NET's own Ping.SendPingAsync to ping asynchronously and specify a timeout:
var ping=new Ping();
var reply=await ping.SendPingAsync(ip,timeout);
return reply.Status==IPStatus.Success;
The PingReply class contains far more detailed information than a simple success/failure. The Status property alone differentiates between routing problems, unreachable destinations, time outs etc
What is the correct way to cancel the following?
var tcpListener = new TcpListener(connection);
tcpListener.Start();
var client = await tcpListener.AcceptTcpClientAsync();
Simply calling tcpListener.Stop() seems to result in an ObjectDisposedException and the AcceptTcpClientAsync method doesn't accept a CancellationToken structure.
Am I totally missing something obvious?
Assuming that you don't want to call the Stop method on the TcpListener class, there's no perfect solution here.
If you're alright with being notified when the operation doesn't complete within a certain time frame, but allowing the original operation to complete, then you can create an extension method, like so:
public static async Task<T> WithWaitCancellation<T>(
this Task<T> task, CancellationToken cancellationToken)
{
// The tasck completion source.
var tcs = new TaskCompletionSource<bool>();
// Register with the cancellation token.
using(cancellationToken.Register( s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs) )
{
// If the task waited on is the cancellation token...
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
}
// Wait for one or the other to complete.
return await task;
}
The above is from Stephen Toub's blog post "How do I cancel non-cancelable async operations?".
The caveat here bears repeating, this doesn't actually cancel the operation, because there is not an overload of the AcceptTcpClientAsync method that takes a CancellationToken, it's not able to be cancelled.
That means that if the extension method indicates that a cancellation did happen, you are cancelling the wait on the callback of the original Task, not cancelling the operation itself.
To that end, that is why I've renamed the method from WithCancellation to WithWaitCancellation to indicate that you are cancelling the wait, not the actual action.
From there, it's easy to use in your code:
// Create the listener.
var tcpListener = new TcpListener(connection);
// Start.
tcpListener.Start();
// The CancellationToken.
var cancellationToken = ...;
// Have to wait on an OperationCanceledException
// to see if it was cancelled.
try
{
// Wait for the client, with the ability to cancel
// the *wait*.
var client = await tcpListener.AcceptTcpClientAsync().
WithWaitCancellation(cancellationToken);
}
catch (AggregateException ae)
{
// Async exceptions are wrapped in
// an AggregateException, so you have to
// look here as well.
}
catch (OperationCancelledException oce)
{
// The operation was cancelled, branch
// code here.
}
Note that you'll have to wrap the call for your client to capture the OperationCanceledException instance thrown if the wait is cancelled.
I've also thrown in an AggregateException catch as exceptions are wrapped when thrown from asynchronous operations (you should test for yourself in this case).
That leaves the question of which approach is a better approach in the face of having a method like the Stop method (basically, anything which violently tears everything down, regardless of what is going on), which of course, depends on your circumstances.
If you are not sharing the resource that you're waiting on (in this case, the TcpListener), then it would probably be a better use of resources to call the abort method and swallow any exceptions that come from operations you're waiting on (you'll have to flip a bit when you call stop and monitor that bit in the other areas you're waiting on an operation). This adds some complexity to the code but if you're concerned about resource utilization and cleaning up as soon as possible, and this choice is available to you, then this is the way to go.
If resource utilization is not an issue and you're comfortable with a more cooperative mechanism, and you're not sharing the resource, then using the WithWaitCancellation method is fine. The pros here are that it's cleaner code, and easier to maintain.
While casperOne's answer is correct, there's a cleaner potential implementation to the WithCancellation (or WithWaitCancellation) extension method that achieves the same goals:
static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
First we have a fast-path optimization by checking whether the task has already completed.
Then we simply register a continuation to the original task and pass on the CancellationToken parameter.
The continuation extracts the original task's result (or exception if there is one) synchronously if possible (TaskContinuationOptions.ExecuteSynchronously) and using a ThreadPool thread if not (TaskScheduler.Default) while observing the CancellationToken for cancellation.
If the original task completes before the CancellationToken is canceled then the returned task stores the result, otherwise the task is canceled and will throw a TaskCancelledException when awaited.
If I write a method that is just wrapping an async method such as this:
public async Task WrapMethodAsync()
{
using(var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAysnc(new MailMessage());
}
}
Is that the same as doing the following:
public Task WrapMethodAsync()
{
using(var smtpClient = new SmtpClient())
{
return smtpClient.SendMailAysnc(new MailMessage());
}
}
Or is the latter not actually running asynchronously?
In this exact scenario the two cases are extremely different because of the using scope.
In the first case you wait (asynchronously) for the SendMailAysnc operation to complete before disposing of the client while in the other case you don't so you would dispose of the client while the operation is still running.
In the general case where there isn't a difference in the general behavior. For example this:
public async Task Run()
{
throw new Exception("stored");
await Task.Delay(-1);
}
VS this:
public Task Run()
{
throw new Exception("thrown");
return Task.Delay(-1);
}
The difference is that the async method has a slight overhead of the whole async mechanism (including a state machine) while the non-async task-returning method has a different exception semantics as exceptions are thrown directly and not stored in the returned task.
The first snippet disposes of the client after the mail is sent, the latter disposes of the client after it starts sending the mail, but before it has finished. Assuming the client isn't supposed to be disposed while it is sending messages, it means that the first solution is very problematic.
Additionally, the error handling semantics are different; exceptions in constructing the Task in the first snippet will result in the method throwing an exception, whereas in the second snippet they result in the return task being marked as Faulted with the appropriate exception set.
If I wanted to write a non-blocking web api action by returning a Task object, I could do it with or without using the async keyword as such:
Using async
public async Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return await task;
}
Without using async
public Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return task;
}
They both work properly. However, every example I've seen (online and in books) on writing a web api action that returns a Task uses the async keyword. Granted, I understand that gives you more flexibility as it allows you to control what you want to "await" on and what not. But assuming your functionality could be effectively handled either way,
Is there any advantage to using one approach vs the other?
Should I always use the async keyword (and if so why)?
Or is it irrelevant?
The async keyword allows you to use an await in your method by creating a state machine. If you can manage returning an asynchronous task without using it you can go ahead and remove it because it has some (very small) overhead. Keep in mind though that it's only useful in a few cases. Your return await is one of them.
Another difference is how exceptions are handled. If there's an exception in the synchronous part of the method and it's marked as async the exception will be stored in the returned task. Without the keyword the exception would be thrown regularly. For example in this case there's a big difference:
var task = Get(); // unhandled exception without async
try
{
var result = await task; // handled exception with async
}
catch
{
}
My recommendation is to use the async keyword even when you don't absolutely need to*, because most developers don't understand the difference and the value in the optimization is mostly negligible.
* Unless you and your teammates really know what you're doing.
There is one advantage to bypassing the await and returning the Task directly: performance. You won't allocate or process the state machine that goes with an async method. There are, however, some subtle differences when exceptions are involved.
In the async example, any exceptions thrown will be enclosed in a Task. This is generally what people assume will happen when they call a Task-returning method. In the sync example, exceptions will be thrown immediately upon invocation.
This will also have an effect on the exception's stack trace. In the async example, it will show Get(). In the sync example, it will show your anonymous delegate or worse, some internal crap in Task.Factory.StartNew with no actual reference to your actual code. This can result in being a little more difficult to debug.
I was new to the async-await method in C# 5.0, and I have few questions in my mind
What is the best way to escape an async method if it failed an input argument or null check?
What is the logical flow of using return; in an Task async method (In some circumstances, it became an infinite loop)?
Is CancellationToken or Task.Yield fit better in this scenario?
public Func<AzureBlobInfo, string, Task> UploadSuccessCallBackAsync { get; set; }
private async Task OnUploadSuccessAsync(AzureBlobInfo info)
{
if (this.UploadSuccessCallBackAsync == null)
{
return;
}
var transactionType = this.FormData.Get("transactionType");
if (string.IsNullOrEmpty(transactionType))
{
transactionType = "unknown";
}
await this.UploadSuccessCallBackAsync(info, transactionType);
}
The best way to "fail upon some problem" IMHO would be to throw the appropriate exception, but you can definitely just use return; if you prefer to avoid exceptions.
This will create a completed/faulted task that was completed synchronously, so the caller using await will get a finished task and continue on using the same thread.
CancellationToken allows for the caller to cancel the operation, which isn't the case you are describing.
Task.Yield doesn't terminate any operation, it just enables other tasks to run for some time and reschedules itself for later.
You can safely return from an async method at any moment. In your case (method returning a Task) the compiler will generate a terminated task, so any caller awaiting on your function will continue.
When throwing an exception from an async method it gets captured in the task so it does not get thrown until the task is observed by calling Task.Wait(), Task.Result, awaiting the task or accessing the Exceptions property of the task.
In terms of input arguments one way to get around that is to split the method into two parts, the first checks the input arguments and then calls the second method which is async. See this questions answer by Stephen Cleary for an example. That way the input argument exception will be thrown straight away outside of the task returned by the method.