Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I wait on tasks without throwing TaskCanceledExceptions?

Tags:

I have a method that creates some Tasks, and then waits on them with WaitAll before returning. The problem is, if those tasks got canceled, then WaitAll throws an AggregateException containing lots of TaskCanceledExceptions.

That means that WaitAll will throw exceptions in two different circumstances:

  • Exceptions that indicate a genuine error. These mean that there was a condition we didn't know how to handle; they need to propagate as unhandled exceptions, until they eventually terminate the process.
  • Exceptions that indicate that the user clicked a Cancel button. These mean that the task was canceled and cleaned up, and the program should continue running normally.

The latter fits squarely into the definition of a vexing exception: it's an exception thrown in a completely non-exceptional circumstance, so I have to catch it in order to resume normal control flow. Fortunately it's easy to catch, right? Just add catch (AggregateException) and -- oh wait, that's the same type that gets thrown when there's a fatal error.

I do need to wait for the tasks to finish running before I return (I need to know that they're no longer using their database connections, file handles, or anything else), so I do need the WaitAll or something similar. And if any of the tasks faulted, I do want those exceptions to propagate as unhandled exceptions. I just don't want exceptions for cancel.

How can I prevent WaitAll from throwing exceptions for canceled tasks?

like image 594
Joe White Avatar asked Dec 30 '11 16:12

Joe White


People also ask

What is task Cancelled exception?

There's 2 likely reasons that a TaskCanceledException would be thrown: Something called Cancel() on the CancellationTokenSource associated with the cancellation token before the task completed. The request timed out, i.e. didn't complete within the timespan you specified on HttpClient. Timeout .

Which method can you use to cancel an ongoing operation that uses CancellationToken?

The CancellationToken is used in asynchronous task. The CancellationTokenSource token is used to signal that the Task should cancel itself. In the above case, the operation will just end when cancellation is requested via Cancel() method.

Which object do you inspect to determine if a long running task will be Cancelled?

For canceling, we use CancellationTokenSource object.


1 Answers

The AggregateException provides a Handle method that can be used for these situations. If for example you want to ignore TaskCanceledException you can do:

var all = new AggregateException(     new NullReferenceException(),     new TaskCanceledException(),     new TaskCanceledException(),     new InvalidOperationException(),     new TaskCanceledException());  try {     throw all; } catch (AggregateException errors) {     errors.Handle(e => e is TaskCanceledException); }  

If all the exceptions are of type TaskCanceledException, the Handle method will not throw any exception; otherwise a new AggregateException containing only the unhandled exceptions will be thrown.

like image 93
João Angelo Avatar answered Nov 09 '22 01:11

João Angelo