Search code examples
c#apiasp.net-corebackground-service

ASP.Net Core Background Service with Task Queue, does it need a Task.Delay?


I have followed the Microsoft documentation on how to implement a BackgroundService with a task queue, but I noticed there's no Task.Delay in the main loop, is it a concern or will it still run fine?

This is the service class in question:

public class BackgroundTasksService : BackgroundService
{
    public IBackgroundTaskQueue TaskQueue { get; }

    public BackgroundTasksService(IBackgroundTaskQueue taskQueue)
    {
        TaskQueue = taskQueue;
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await BackgroundProcessing(stoppingToken);
    }

    private async Task BackgroundProcessing(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var workItem =
                await TaskQueue.DequeueAsync(stoppingToken);

            try
            {
                await workItem(stoppingToken);
            }
            catch (Exception ex)
            {
            }
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        await base.StopAsync(stoppingToken);
    }
}

This code was taken from

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-5.0&tabs=visual-studio#queued-background-tasks


Solution

  • The answer lies in what is happening if this code executes while there is nothing in the queue.

    var workItem = await TaskQueue.DequeueAsync(stoppingToken);

    The answer is that nothing is happening. This line of code doesn't execute over and over again until something is dequeued. That's why there's no need for a delay.

    It also doesn't block until something is dequeued.

    What happens is that the thread executing the method is freed to do something else. No thread is dedicated to the execution of DequeueAsync. (See this excellent post - There Is No Thread.)

    When and if an item appears in the queue to be dequeued, then an available thread is assigned to resume execution of the method.

    DequeueAsync only throws an exception if

    • the cancellation token is canceled
    • the queue's Complete method is called and the queue is empty, which means that you're no longer expecting anything to appear in the queue.