Home > Mobile >  Using Task.WhenAll but each individual Task's success needs to be tracked
Using Task.WhenAll but each individual Task's success needs to be tracked

Time:02-25

The original method is the inefficient foreach loop that awaits every job (which is an I/O bound network call):

foreach (var job in Jobs)
{
    try
    {
        await DoJobAsync(job); //Pass job to external vendor API
        job.Succeeded = true;
    }
    
    catch (Exception)
    {
        //do nothing, let loop continue
    }
}

Now to improve performance, I want to use Task.WhenAll to process all jobs in a non-blocking manner.

However, we need to make sure that each job object only has that Succeeded property set to true if the DoJobAsync task does not throw exception.

If we do this:

await Task.WhenAll(Jobs.Select(j =>
{
    var task = DoJobAsync(j);
    j.Succeeded = true;
    return task;
}));

My understanding is that if any job task ends up throwing exception, that property will still get toggled to true because each individual task is not awaited as it is created, making the code flow go right past it.

I know I can capture the Task returned by Task.WhenAll to have access to a list of all exceptions thrown, but I can't figure out a way to use them to trace back to the job that threw the exception.

How do I work around this issue?

CodePudding user response:

Return the result true/false from the method DoJobAsync().

This way you can return the result directly.

await Task.WhenAll(Jobs.Select(j =>
{
    return DoJobAsync(j);
}));

CodePudding user response:

You could use an async delegate as the selector of the Select operator:

await Task.WhenAll(Jobs.Select(async job =>
{
    await DoJobAsync(job);
    job.Succeeded = true;
}));

This way each job will be projected to a Task that will not be the original DoJobAsync(job) task, but instead a wrapper task that encapsulates the logic for updating the Succeeded property. This property will be updated immediately after the DoJobAsync(job) task completes successfully.

It is possible that multiple Job objects might have their Succeeded property updated in parallel. It depends on whether a SynchronizationContext is installed on the current thread.

  • Related