I have a task created as follows.
var task = Task.Factory.FromAsync<Request, Response>(
service.BeginOp,
service.EndOp,
request,
null);
When I await the task in a try/catch, the exception is not caught.
try
{
await task;
}
catch (Exception e)
{
// Block never reached
}
However when I use ContinueWith(), the exception is caught.
await task.ContinueWith(t =>
{
if (t.Exception != null)
{
// Block reached
}
});
Why is it not caught in the first case? I have try/caught other Tasks and it catches the exception.
I suspect that further up your call stack, your code is calling Task<T>.Result or Task.Wait. This will cause a deadlock, as I explain on my blog.
By default, await will capture a "context" whenever it awaits a Task. In this case, the "context" is the ASP.NET request context, which only allows one thread in at a time. If your code blocks a thread within that request context (e.g., by calling Result/Wait), then when the task completes, it cannot resume executing the async method because the context only allows one thread in.
Turns out that in the above callstack I was not using await. I am not sure why the compiler allowed this. Adding the await fixed the problem.
Related
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
I have a job like this:
[UnitOfWork]
public override void Execute(CompleteIRHJobArgs args)
{
var robotUserId = _userRepo.GetAll().Where(p => p.UserName == TestaLIMSWPConsts.LIMSRobot).Select(p => p.Id).First();
using (_session.Use(args.TenantId, robotUserId))
{
_instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds);
}
}
I find robotUserId and set it as the current user. But after I step into method SetIRHToCompleteState, _session.UserId.Value is null. I think it is wrong behavior. My ABP version is 4.0.0.
public async Task SetIRHToCompleteState(List<int> irhIds)
{
var irhs = await _instanceHeaderRepo.GetAll().Where(p => irhIds.Contains(p.Id)).ToListAsync();
foreach (var t in irhs)
{
t.FlowState = FlowState.Completed;
t.CompleteDate = Clock.Now;
t.CompleteUserId = _session.UserId.Value;
}
}
And sometimes,
var irhs = await _instanceHeaderRepo.GetAll()...
throws exception:
System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---> System.Data.SqlClient.SqlException: There is already an open DataReader associated with this Command which must be closed first. ---> System.ComponentModel.Win32Exception: The wait operation timed out
But after step into method SetIRHToCompleteState, _session.UserId.Value is null.
SetIRHToCompleteState is async and continued running after the using scope was disposed.
Since Execute is not async, you cannot await but you can call AsyncHelper.RunSync instead.
// using Abp.Threading;
using (_session.Use(args.TenantId, robotUserId))
{
AsyncHelper.RunSync(() => _instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds));
}
This would also avoid the "open DataReader" error.
From aspnetboilerplate/aspnetboilerplate#1646:
it's called in a background thread which is not inside an async context. But it's not a problem since background job manager is already single threaded and does not cause to block many threads.
Hangfire implementation is also like that.
Consider the following code
import 'dart:async';
Future main() async {
try {
print("trying");
await doSomething();
print("success");
} catch (e) {
print("caught");
}
}
Future<int> doSomething() async {
await doSomethingElse();
return 5;
}
Future<int> doSomethingElse() async {
throw new Exception();
}
When run, the exception thrown in doSomethingElse() is caught up in main(), and everything works as expected. But, say the person who wrote the doSomething() method didn't realize that doSomethingElse() was asynchronous, and instead wrote the follow (note the missing await).
Future<int> doSomething() async {
doSomethingElse();
return 5;
}
Now the exception isn't caught at all. Rather, the output now looks like this:
trying
success
Unhandled exception:
Uncaught Error: Exception
Stack Trace:
#0 doSomethingElse.<doSomethingElse_async_body> (file:///C:/code/test.dart:19:7)
#1 Future.Future.<anonymous closure> (dart:async/future.dart:118)
<snip>
What's happening is that doSomething() is returning immediately, and then sometime later, in another context, doSomethingElse() is throwing its error, stopping all execution immediately. I know that an answer to this might be "Well, don't do that then." but I'm considering cases where I might not have control over the methods I'm calling (say if they are part of a library).
This situation leads to a couple of related questions:
As the author of main(), is there any way I can be certain that my call to doSomething() won't end with an unhandled exception? Or am I dependent on the author of doSomething() to make sure all possible exceptions are handled or propagated to the returned Future? Is there a way to attach some sort of global error handler that can catch errors from abandoned Futures?
As the author of doSomething(), if I don't want to wait on doSomethingElse() (say it writes to a log for example, so I neither need the output nor do I need to worry about handling errors). Is there anything I can do to prevent errors in doSomethingElse() from halting the program other than wrapping every call of it a try/catch block (which can be cumbersome an easily overlooked)?
As the author of doSomethingElse(), is there some pattern I can use which allows me to throw Exceptions in a way that callers who wait for the Future to complete can handle that Exception themselves whereas callers that don't wait for the Future don't have to worry about catching the Exception? My best thought in that regard is to return a special object rather than throwing an Exception, but that adds a lot of extra cruft and makes the method much harder use.
Note: I'm using async/await syntax here, but the question should be equally relevant for a more strictly Future based construction (where you return a new Future in doSomething() instead of .then()ing off the one from doSomethingElse()
Uncaught asynchronous errors are handled to the current zone's error handler.
What you are seeing is the root-zone's error handler reporting the error as uncaught, which also terminates the isolate.
What you want is to introduce a different error handler for your code, by running it through runZoned with an error handler:
import "dart:async";
main() {
runZoned(() async {
try {
print("trying");
await doSomething();
print("success");
} catch (e) {
print("caught");
}
}, onError: (e, s) {
print("uncaught");
});
}
Like Greg pointed in its comment you can use Zones to catch unexpected errors from async code.
I'm using a "Post" async method of webApi rest service:
public async Task<object> Post([FromBody]string data)
{
object response = ExecuteServerLogics(data);
return response;
}
This above code worked good but in some of the client's calls, we experienced performance issues.
After reading some articles here, i've noticed that our webApi rest service,
is not really working asynchronously with its incoming web requests,
because we forgot to use async/await pattern :
public async Task<object> Post([FromBody]string data)
{
object response = await Task<object>.Run( () =>
{
return ExecuteServerLogics(data);
});
return response;
}
After this fix we noticed the performance got better,
but we found another critic problem:
when accessing HttpContext.Current - it returns Null reference:
public async Task<object> Post([FromBody]string data)
{
object response = await Task<object>.Run( () =>
{
var currentContext = HttpContext.Current; // Returns Null!
return ExecuteServerLogics(data);
});
return response;
}
We tried to found a solution for it, and in most posts we found that we should pass the
worker thread's HttpContext reference into the inner Task that executes the server logics.
The problem with this solution is that the server's logics methods, use many static classes that use
"HttpContext.Current" such as -
Loggers calls.
static security classes that retrieves the user.identity
static security classes that retrives the incoming request's session data, etc.
Therefore, passing the "HttpContext.Current" reference of the worker thread won't solve it.
When we tried the next solution:
public async Task<object> Post([FromBody]string data)
{
// Save worker context:
var currentContext = HttpContext.Current;
object response = await Task<object>.Run( () =>
{
// Set the context of the current task :
HttpContext.Current = currentContext ; // Causes the calls not to work asynchronously for some reason!
// Executes logics for current request:
return ExecuteServerLogics(data);
});
return response;
}
for some reason, we noticed the performance got worse again, like it had returned working synchronously again.
Our problems are:
1. Why in the last example, setting the "HttpContext.Current" inside the await task,
causes the requests to return the same bad performance results which similar to the synchronous results?
2. Is there another way we can use "HttpContext.Current" inside the inner task that call - "ExecuteServerLogics",
and in all the static classes which also call "HttpContext.Current"?
am I doing the entire design wrong somehow?
Thanks!
From the beginning:
public async Task<object> Post([FromBody]string data)
{
object response = ExecuteServerLogics(data);
return response;
}
Don't ignore compiler warnings; the compiler will generate a warning for this method that specifically states it will run synchronously.
Moving on:
in some of the client's calls, we experienced performance issues.
Asynchronous code on the server will not be faster for a single call in isolation. It only helps you scale your server.
In particular, Task.Run will negate all the performance benefits of async and then degrade performance a bit beyond that. I believe the improvement in performance that you measured was coincidental.
in most posts we found that we should pass the worker thread's HttpContext reference into the inner Task that executes the server logics.
Those posts are wrong. IMHO. You end up using the HttpContext object from a background thread, when that object is specifically designed to be only accessed from a request thread.
am I doing the entire design wrong somehow?
I do recommend you take a step back and think about the big picture. When a request comes in, it has a certain amount of work to do. Whether that work is done synchronously or asynchronously is immaterial to the client; both approaches will take about the same amount of time.
If you need to return early to the client, then you'll need a completely different architecture. The usual approach is to queue the work to a reliable queue (e.g., Azure queue), have a separate backend (e.g., Azure WebRole), and proactively notify the client when the work is completed (e.g., SignalR).
That's not to say that async is useless, though. If ExecuteServerLogics is an I/O bound method, then it should be made asynchronous rather than blocking, and then you can use asynchronous methods as such:
public async Task<object> Post([FromBody]string data)
{
object response = await ExecuteServerLogicsAsync(data);
return response;
}
This will enable your server to be more responsive and scalable overall (i.e., not get overwhelmed by many requests).
If your task is inside your ApiController-derived class, you can use:
var ctx = this.Request.Properties["MS_HttpContext"] as System.Web.HttpContextWrapper;
This will give you an HttpContext wrapper with all the usual properties.
Amir I think you're looking for something like this below. I've been dealing with the same issue, trying to optimize a series of calls. It needs to be async all the way through, which means your ExecuteServerLogics() would need to be async, and you'd have to mark the containing lamda as async as well.
I believe following that pattern you can probably eliminate most of your performance issues. Nice passing the context through like that.
public async Task<object> Post([FromBody]string data)
{
// Save worker context:
var currentContext = HttpContext.Current;
object response = await Task<object>.Run(async () =>
{
// Set the context of the current task :
HttpContext.Current = currentContext ;
// Executes logics for current request:
return await ExecuteServerLogics(data);
});
return response;
}
I'm experiencing problems with an exception not caught in my workflows.
I have a custom AsyncCodeActivity surrounded by a TryCatch; anyway, the exception is not caught and, worse, my IIS pool hosting the workflow is sometimes restarted.
Looking at this question/answer (Exception escapes from workflow despite TryCatch activity), I'm thinking that the problem is in the way I rethrow exceptions. This is how I usually write async code activities:
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
Action<object> execute = s => this.Execute();
var task = new Task(execute, state, CancellationToken.None, TaskCreationOptions.PreferFairness);
task.ContinueWith(s => callback(s));
task.Start();
return task;
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
var task = result as Task;
Contract.Assert(task != null);
if (task.IsFaulted && task.Exception != null)
{
Contract.Assert(
task.Exception.InnerException != null,
"It is expected that the inner exception in a task is not null");
const string Message = "An exception was thrown while doing something";
Logger.ErrorException(Message, task.Exception.InnerException);
throw new WorkflowApplicationException(Message, task.Exception.InnerException);
}
}
private void Execute()
{
// Do something here
}
Is it the correct way to handle exceptions in async code activities? if yes, how should I prevent my workflow from aborting (and sometimes restarting IIS)?
Thanks
I don't think WorkflowApplicationException was meant to be thrown by your code. I wouldn't be surprised if somewhere we are treating this exception differently and not invoking the TryCatch block because this exception (and it's subclasses) are typically thrown by the workflow runtime and there wouldn't be a point of catching them in an activity if the runtime is hosed.
You could try throwing a different exception to see if that makes a difference.