Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when you await a failed task

I have a theoretical question to you. What happens if I await the Result of a Task inside another task? I want to know if my current system will work afterwards.

A task gets launched and does some stuff. At some point that task might need another one in order to process data which the current task is not able to process by itself. So I use await to ensure that the current task won't continue as long as he has not the result of the helper task. But what happens if the helper fails? Will the current task remain locked?

Can I avoid this deadlock somehow (without changing the system itself - task inside task)?

like image 346
SharpShade Avatar asked Sep 27 '14 19:09

SharpShade


People also ask

What happens if we do not await a task?

If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.

Does await halt execution?

See example below. Because await is only valid inside async functions and modules, which themselves are asynchronous and return promises, the await expression never blocks the main thread and only defers execution of code that actually depends on the result, i.e. anything after the await expression.

Is await the same as task wait?

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.

What happens if you don't wait for a task C#?

Nothing. The code ignores the task, so the task is ignored.


2 Answers

A task gets launched and does some stuff. At some point that task might need another one in order to process data which the current task is not able to process by itself. So I use await to ensure that the current task won't continue as long as he has not the result of the helper task. But what happens if the helper fails? Will the current task remain locked?

The core idea behind async and await is that asynchronous code works just about the same as synchronous code.

So, if you have synchronous code like this:

void HelperMethod()
{
  throw new InvalidOperationException("test");
}

void DoStuff()
{
  HelperMethod();
}

then you would expect DoStuff to propagate the InvalidOperationException from the helper method. Similarly, that's what happens with asynchronous code:

async Task HelperMethodAsync()
{
    throw new InvalidOperationException("test");
}

async Task DoStuffAsync()
{
    await HelperMethodAsync();
}

That is, DoStuffAsync will also propagate the InvalidOperationException.

Now, it doesn't work exactly the same way, of course, since it must be asynchronous, but the general idea is that all your control flow such as try/catch, for loops, etc, all "just work" for asynchronous code very similarly to synchronous code.

What's actually going on is that when HelperMethod ends with an InvalidOperationException, the exception is caught and placed on the returned Task, and the task is completed. When the await in DoStuffAsync sees that the task has completed, it examines its exceptions and re-raises the first one (in this case, there is only one, the InvalidOperationException). And it re-raises it in a way that preserves the call stack on the exception. This in turn causes the Task returned from DoStuffAsync to be completed with that same exception.

So, under the covers async and await are doing a bit of work to ensure that you can just call other methods with await and use try/catch the same way as you would in synchronous code. But most of the time you don't have to be aware of that.

like image 200
Stephen Cleary Avatar answered Sep 16 '22 15:09

Stephen Cleary


It's really easy to test. For example:

[TestMethod, ExpectedException(typeof(Exception))]
public async Task DoFaultedTaskThrowOnAwait()
{
  var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
  await task;
}

[TestMethod, ExpectedException(typeof(AggregateException))]
public void DoFaultedTaskThrowOnWait()
{
  var task = Task.Factory.StartNew(() => { throw new Exception("Error 42"); });
  task.Wait();
}

Both tests pass, notice that Wait throws an AggregateException, and await throws the Exception.

like image 36
Peter Ritchie Avatar answered Sep 18 '22 15:09

Peter Ritchie