Search code examples
c#async-awaittask-parallel-library

Execute multiple async tasks sequentially, continuing on exception


I'd like to execute multiple async tasks sequentially.

foreach (var msg in messages)
{
    await smtp.SendAsync(msg);
}

However, if one of the tasks fails, I'd like the rest of them to continue. And throw one exception at the end.

Think of it like .WhenAll() that executes all the tasks and throws an AggregateException at the end, if any of the tasks fails. However, I cannot find any sequential alternative.

I studied the docs and googled and stackoverflowed for a solution, and I found no built-in way to do this. I think the only way is to handle exceptions manually.

Something like this

var exceptions = new List<Exception>();
foreach (var msg in messages)
{
    try
    {
        await smtp.SendAsync(msg).ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        exceptions.Add(ex);
    }
}
if (exceptions.Count > 0) 
{
    throw new AggregateException(exceptions);
}

Questions:

  1. Is there a .NET built-in solution I'm missing?
  2. If not, is this the right way? Maybe chaining multiple .ContinueWith calls and returning the resulting "chain-task" instead is considered a better practice? (thus eliding await/async and prevent unnecessary state-machine building)
  3. Am I allowed to use the .NET built-in AggregateException here or this is bad practice?

Solution

  • Is there a .NET built-in solution I'm missing?

    No. This is an unusual need, so there's nothing built-in. When doing sequential operations, it's far more common to want to stop on the first exception.

    If not, is this the right way?

    Yes. You can use AggregateException if that's the semantics you want. You should prefer await over ContinueWith.

    You may also want to consider a railway programming pattern. There isn't anything like a Try/Error/Exceptional monad in the BCL but there are several libraries out there to fill that gap