Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing WhenAll on QueueBackgroundWorkItem

I need to spawn some long running tasks in ASP.NET WebAPI, and I chose to do that using QueueBackgroundWorkItem.

My question is -

I need to implement a WhenAll mechanism with those tasks, meaning - I need to know when some tasks has finished, and then to perform some other task.

How can that be done using QueueBackgroundWorkItem? I couldn't find a way to do that, since it returns void, and accepts Action.

Thanks!

like image 278
ml123 Avatar asked Dec 19 '25 05:12

ml123


1 Answers

You can use TaskCompletionSource to create a helper method like this:

public static Task RunViaQueueBackgroundWorkItem(Action<CancellationToken> action)
{
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    HostingEnvironment.QueueBackgroundWorkItem((ct) =>
    {
        try
        {
            action(ct);

            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled();
            else
                tcs.TrySetResult(0);
        }
        catch (Exception ex)
        {
            tcs.TrySetException(ex);
        }
    });

    return tcs.Task;
}

This method will return a task that will complete after the action completes. Note that it handles the case where an exception occurs during the invocation of the action. It also handles the case if cancellation is requested.

Here is an example of how you can use it:

public async Task<string> Get(int id)
{
    var t1 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask1(ct));
    var t2 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask2(ct));

    await Task.WhenAll(t1, t2);

    //...
}

For completeness, here is the helper method for the other overload of QueueBackgroundWorkItem:

public static Task RunViaQueueBackgroundWorkItem(Func<CancellationToken,Task> asyncAction)
{
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    HostingEnvironment.QueueBackgroundWorkItem(async (ct) => 
    {
        try
        {
            await asyncAction(ct);

            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled();
            else
                tcs.TrySetResult(0);
        }
        catch (Exception ex)
        {
            tcs.TrySetException(ex);
        }
    });

    return tcs.Task;
}
like image 132
Yacoub Massad Avatar answered Dec 20 '25 19:12

Yacoub Massad