Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Task.WhenAny() with a predicate

I want to execute several asynchronous tasks concurrently. Each task will run an HTTP request that can either complete successfully or throw an exception. I need to await until the first task completes successfully, or until all the tasks have failed.

How can I implement an overload of the Task.WhenAny method that accepts a predicate, so that I can exclude the non-successfully completed tasks?

like image 703
T. Gilad Avatar asked Dec 07 '22 21:12

T. Gilad


1 Answers

Wait for any task and return the task if the condition is met. Otherwise wait again for the other tasks until there is no more task to wait for.

public static async Task<Task> WhenAny( IEnumerable<Task> tasks, Predicate<Task> condition )
{
    var tasklist = tasks.ToList();
    while ( tasklist.Count > 0 )
    {
        var task = await Task.WhenAny( tasklist );
        if ( condition( task ) )
            return task;
        tasklist.Remove( task );
    }
    return null;
}

simple check for that

var tasks = new List<Task> {
    Task.FromException( new Exception() ),
    Task.FromException( new Exception() ),
    Task.FromException( new Exception() ),
    Task.CompletedTask, };

var completedTask = WhenAny( tasks, t => t.Status == TaskStatus.RanToCompletion ).Result;

if ( tasks.IndexOf( completedTask ) != 3 )
    throw new Exception( "not expected" );
like image 199
Sir Rufo Avatar answered Dec 24 '22 11:12

Sir Rufo