Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignore the Tasks throwing Exceptions at Task.WhenAll and get only the completed results

I am working on a Task parallel problem that I have many Tasks that may or may not throw Exception.

I want to process all the tasks that finishes properly and log the rest. The Task.WhenAll propage the Task exception without allowing me to gather the rest results.

    static readonly Task<string> NormalTask1 = Task.FromResult("Task result 1");
    static readonly Task<string> NormalTask2 = Task.FromResult("Task result 2");
    static readonly Task<string> ExceptionTk = Task.FromException<string>(new Exception("Bad Task"));
    var results = await Task.WhenAll(new []{ NormalTask1,NormalTask2,ExceptionTk});

The Task.WhenAll with throw the Exception of ExcceptionTk ignoring the rest results. How I can get the results ignoring the Exception and log the exception at same time?

I could wrap the task into another task that try{...}catch(){...} the internal exception but I don't have access to them and I hope I will not have to add this overhead.

like image 737
Menelaos Vergis Avatar asked Sep 20 '16 08:09

Menelaos Vergis


People also ask

Does task WhenAll throw exception?

WhenAll(tasklist)", it will throw an exception if any of the tasks are faulted.

How does task WhenAll work?

WhenAll method to a collection of tasks. The application of WhenAll returns a single task that isn't complete until every task in the collection is completed. The tasks appear to run in parallel, but no additional threads are created. The tasks can complete in any order.

Does task WhenAll start the tasks?

WhenAll starts both Tasks at the same time and executes them in parallel, the outcome is that instead of taking 3 seconds to run the program it just takes 2 seconds, that's a huge performance enhancement!

How do I handle Task run exception?

Tasks Module Example Public Sub Main() Dim task1 = Task. Run(Sub() Throw New CustomException("This exception is expected!")) Try task1. Wait() Catch ae As AggregateException ' Call the Handle method to handle the custom exception, ' otherwise rethrow the exception.


1 Answers

You can create a method like this to use instead of Task.WhenAll:

public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{    
    return Task.WhenAll(
        tasks.Select(
            task => task.ContinueWith(
                t => t.IsFaulted
                    ? new ResultOrException<T>(t.Exception)
                    : new ResultOrException<T>(t.Result))));
}


public class ResultOrException<T>
{
    public ResultOrException(T result)
    {
        IsSuccess = true;
        Result = result;
    }

    public ResultOrException(Exception ex)
    {
        IsSuccess = false;
        Exception = ex;
    }

    public bool IsSuccess { get; }
    public T Result { get; }
    public Exception Exception { get; }
}

Then you can check each result to see if it was successful or not.


EDIT: the code above doesn't handle cancellation; here's an alternative implementation:

public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{    
    return Task.WhenAll(tasks.Select(task => WrapResultOrException(task)));
}

private async Task<ResultOrException<T>> WrapResultOrException<T>(Task<T> task)
{
    try
    {           
        var result = await task;
        return new ResultOrException<T>(result);
    }
    catch (Exception ex)
    {
        return new ResultOrException<T>(ex);
    }
}
like image 124
Thomas Levesque Avatar answered Sep 16 '22 13:09

Thomas Levesque