Search code examples
c#tasktpl-dataflow

Understanding exception handling in ActionBlock


Can someone explain why the first code block will throw when we await the completion of the action block while second code block doesn't? There isn't any chaining of dataflow blocks so no propagation is required.

ActionBlock definition 1:

ActionBlock<int> workerBlock = new ActionBlock<int>(async (i) =>
{
    await Task.Delay(1);
    throw new OperationCanceledException();
});

ActionBlock definition 2:

ActionBlock<int> workerBlock = new ActionBlock<int>(async (i) =>
{
    await ExceptionThrower1();
});


private static async Task ExceptionThrower1()
{
    CancellationTokenSource source= new CancellationTokenSource();
    source.CancelAfter(100);
    await ExceptionThrower2(source.Token);
}

private static async Task ExceptionThrower2(CancellationToken token)
{
    await Task.Delay(1000);
    try
    {
        token.ThrowIfCancellationRequested();
    }
    catch (OperationCanceledException e)
    {
        Console.WriteLine(e);
        throw;
    }
}

Test program:

workerBlock.SendAsync(1).GetAwaiter().GetResult();
workerBlock.SendAsync(1).GetAwaiter().GetResult();
workerBlock.SendAsync(1).GetAwaiter().GetResult();

workerBlock.Complete();
workerBlock.Completion.GetAwaiter().GetResult();
Console.WriteLine("Done");

If I use the first definition, "Done" doesn't get printed because awaiting the completion throws the exception. In the second definition, "Done" gets printed, though I can see the exceptions being printed out in ExceptionThrower2.

Based on this blogpost - https://blogs.msdn.microsoft.com/pfxteam/2011/11/09/exception-handling-in-tpl-dataflow-networks/ even the second one should be considered and unhandled exception and get thrown on completion right?


Solution

  • I was unable to replicate the behaviour you described, in my case "Done" was printed every time. However OperationCanceledException comes under the category of "Exceptions That Indicate Cooperative Cancellation" have a look at Exception Handling (Task Parallel Library) and search for OperationCanceledException.