Search code examples
tpl-dataflow

Expecting to catch an Aggregate Exception


I am trying to understand exception handling in TPL Dataflow so I can effectively handle errors. In my comment numbered 1. below I am expecting to catch an AggregateException but everything just halts and doesn't recover. If I remove the throw (2.) then the ActionBlock continues to process but again, the AggregateException handler doesn't trigger.

Would anyone be able to help with an explanation to improve my intuition.

Would also welcome any documentation references on the topic.

async Task Main()
{
    var ab = new System.Threading.Tasks.Dataflow.ActionBlock<int>(async a => {
        try
        {
            await Task.Delay(100);
            if (a == 7)
            {
                throw new Exception("Failed");
            }
            else
            {
                Console.WriteLine(a);
            }
        }
        catch (Exception ie)
        {
            Console.WriteLine(ie.Message);
            throw;  //2. This causes the actionblock to halt, removing allows block to continue
        }

    });

    for (int i = 0; i < 10; i++)
    {
        await ab.SendAsync(i);
    }
    ab.Complete();

    try
    {
        await ab.Completion;
    }
    catch (AggregateException ae)
    {
        Console.WriteLine(ae.Flatten().Message);
        // 1. Expecting to catch here.
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}


Solution

  • What you're seeing is the await unwrapping your Aggregate Exception. When you await the completion task the exception is unwrapped and thrown to the general exception catch. But if you don't unwrap the exception then you'd see the exception caught as an aggregate exception like this:

    try
    {
        ab.Completion.Wait();
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("Aggregate Exception");
        // 1. Expecting to catch here.
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception Caught");
    }
    

    It's obviously better to properly await the completion but this samples shows you that indeed an AggregateExcpetion is caught when it's not unwrapped.