TPL and Error Handling & Continuation Tasks

Two of my colleagues (one from work and one from a user group) kindly pointed out to me that in my last post I omitted Continuation Tasks as a means of Error Handling for the TPL. As such, I will expand upon my last post with an example of handling errors via a Continuation Task.

Continuing where we left off last, the following code will utilize a Task Continuation to handle errors within Tasks.

static void Main(string[] args)
{
    for (int i = 0; i < 5; i++)
    {
        // Initialize a Task which throws exception
        var task = new Task(() =>
        {
            throw new Exception("It broke!");
        });
        // Configure the Continuation to only fire on error
        task.ContinueWith(HandleError, TaskContinuationOptions.OnlyOnFaulted);

        // Start the Task
        task.Start();
    }

    Console.WriteLine("End of method reached");
    Console.ReadKey();
}

private static void HandleError(Task task)
{
    // The Task has an AggregateException
    var agex = task.Exception;
    if (agex != null)
    {
        // Output all actual Exceptions
        foreach (var ex in agex.InnerExceptions)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

And the result:

/img/tpl-and-error-handling-2-first-output.png

The Output

By using a Continuation Task which wraps our private method, HandleError (a method whose signature is effectively Action), we can effectively handle errors in a more elegant, less inline way. This allows centralizing Task handling logic in such cases as where you’d always want to log to a file or database, for example. Note that there is overhead in the complexity of this architecture – since we receive an AggregateException, we must loop through it to analyze our individual errors.

Sorry that I missed this in my first post!


See also