Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Under what circumstances will awaiting a cancelled task throw TaskCanceledException?

Tags:

c#

async-await

I'm used to being able to perform an asynchronous pattern when handling cancellation of asynchronous operations:

public async Task InvokeAsync(CancellationToken cancellationToken)
{
    using(cancellationToken.Register(handler.Stop))
    {
        try
        {
            await handler.HandleAsync();
        }
        catch(HandlerStoppedException ex)
        {
            cancellationToken.ThrowIfCancellationRequested();
            throw;
        }
    }
}

The method calls an asynchronous component which exposes some kind of cancel mechanism. The cancellation token sets up a callback to invoke the cancel mechanism when the token signals cancellation is requested.

I can call this method in my tests to exercise its function within a timeout.

async Task TestInvoke()
{
    using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10))
    {
        try
        {
            await InvokeAsync(timeout.Token);
        }
        catch (TaskCancelledException ex)
        {
            if (ex.CancellationToken == timeout.Token)
            {
                throw new TimeoutException(
                    "Operation failed to complete in the allowed time.", ex);
            }

            throw;
        }
    }
}

My expectation is that throwing OperationCanceledException within an async method will cause the Task returned by the method to transition to the "Canceled" state. I then expect any attempts to await this cancelled task should throw a TaskCanceledException.

In my current scenario (code very similar to above) I instead get an OperationCanceledException when I await the task. If I examine the state of the task, I can see it is in a "Canceled" state and has no exception associated with it.

More curiously, if I call Wait() on the task, it throws an AggregateException containing the expected TaskCanceledException instead.

Under what circumstances will awaiting a cancelled task throw OperationCanceledException instead of the more typical TaskCanceledException?

like image 364
Paul Turner Avatar asked Mar 09 '23 13:03

Paul Turner


1 Answers

Under what circumstances will awaiting a cancelled task throw OperationCanceledException instead of the more typical TaskCanceledException?

This question is too broad. Even if one enumerated all scenarios where that happens today, it could change tomorrow.

Instead, I'll say this:

  • TaskCanceledException is not "more typical". It was originally used in dynamic task-based parallelism, which has nothing to do with asynchronous programming.
  • OperationCanceledException is a base class for TaskCanceledException. In your code, you should never catch TaskCanceledException (unless you are doing dynamic task-based parallelism and need to access TaskCanceledException.Task).

Just catch OperationCanceledException instead.

like image 61
Stephen Cleary Avatar answered Apr 09 '23 00:04

Stephen Cleary