Continuation tasks in .NET TPL: exception handling in task chains

We saw in previous posts on TPL how to chain tasks using the ContinueWhenAll and ContinueWhenAny methods. We also discussed strategies of exception handling in tasks. If you don’t know how to use these techniques make sure to read those posts first.

If you have multiple tasks chained together then special care should be taken when handling exceptions. There’s no automatic way to propagate an exception thrown by a task to the continuation task(s). However, the continuation task can always check the status of the antecedent and extract any exceptions. It can then process it in some way.

We start the first task:

Task antecedentTask = Task.Factory.StartNew(() =>
{
	Console.WriteLine("Mother of all tasks.");
});

The first continuation task throws an exception:

Task continuationTaskWithException = antecedentTask.ContinueWith(antecedent =>
{
	Console.WriteLine("Task that throws an exception.");
	throw new Exception();
});

The continuation of the continuation checks the status of the above task and re-throws the inner exception of its aggregate exception:

Task taskToRunAfterExceptionTask = continuationTaskWithException.ContinueWith(antecedent =>
{
	if (antecedent.Status == TaskStatus.Faulted)
	{
		throw antecedent.Exception.InnerException;
	}
	Console.WriteLine("Task that checks if previous task has faulted.");
});

We wait for the second continuation task to finish and handle the aggregate exception in some way:

try
{
	taskToRunAfterExceptionTask.Wait();
}
catch (AggregateException ex)
{
	ex.Handle(innerException =>
	{
		Console.WriteLine("Handled exception is of type: {0}", innerException.GetType());
		return true;
	});
}

If the second continuation task does not check the status of the task before that then the exception thrown by continuationTaskWithException will remain unhandled.

You can handle exceptions in a similar way when doing multitask continuations:

Task<int>[] motherTasks = new Task<int>[10];

Task<int> continuation = Task.Factory.ContinueWhenAll<int>(motherTasks, antecedents =>
{
	foreach (Task<int> task in antecedents)
	{
		if (task.Status == TaskStatus.Faulted)
		{
			//do something with the exception
		}
		else
		{
			//normal operations
		}
	}
	return 1234;
});

Handling exceptions in a ContinueWhenAny scenario is somewhat more complicated. Recall that even if a continuation task will have one antecedent – the one that finishes first – the other tasks in the antecedent task array will continue to run in the background. If one of those background tasks throws an exception then it will remain unhandled. A possible solution is to use ContinueWhenAll only for exception handling purposes:

Task<int>[] motherTasks = new Task<int>[10];

Task continuationTask = Task.Factory.ContinueWhenAny<int>(motherTasks,
	(Task<int> antecedent) =>
	{
		Console.WriteLine("Continuation task.");
	}, TaskContinuationOptions.NotOnFaulted);

Task exceptionHandlingContinuation = Task.Factory.ContinueWhenAll(motherTasks
	, antecedents =>
		{
			foreach (Task task in antecedents)
			{
				if (task.Status == TaskStatus.Faulted)
				{
					//exception handling code here
				}
			}
		});

View the list of posts on the Task Parallel Library here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

One Response to Continuation tasks in .NET TPL: exception handling in task chains

  1. firo says:

    throw antecedent.Exception.InnerException; will throw away the original stack trace. There must a better way to propagate just the inner exception.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT BEST PRACTICES WITH MICROSOFT STACK & ANGULAR

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: