Categories
ASP.NET Core

Background Tasks with ASP.NET Core 3.1

In the past, running a background task used to mean writing code to spin up a new thread. Then the Task Parallel Library came along with the async & await keywords making it easier to run tasks in the background. In ASP.NET Core 3.1 there is a new feature which makes starting services with websites even easier.

Give me the code… https://github.com/JakeDixon/background-services-with-asp-net-core

The IHostedService interface enables you to write background tasks that can be started and stopped with the website. The interface provides two methods:
StartAsync(CancellationToken stoppingToken)
and
StopAsync(CancellationToken stoppingToken)

I’m going to defer to the ASP.NET Core documentation for examples of the interface because it’s well covered. https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

What I actually want to show to you is the BackgroundService class and how we can inherit that to simplify implementation. The BackgroundService class implements the IHostedService interface for us. The class also brings a new method ExecuteAsync(CancellationToken stoppingToken).

With the ExecuteAsync method we don’t need to worry about the StartAsync and StopAsync methods. We can focus on our logic for the background task therefore keeping a cleaner code base.

Short Running Background Tasks

Tasks where you only want to run something at start up quickly can have the logic put directly into the ExecuteAsync method and it will execute every time the website is started.

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace BackgroundTasksASPNETCore.Services
{
    public class ShortRunningSingleTaskService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // simulate quick logic
            await Task.Delay(200);
        }
    }
}

Long Running Background Tasks

Longer running single tasks should pay attention to the stoppingToken.IsCancellationRequested in order to keep responsiveness high. Responding to the cancellation takes some extra consideration, like what if we were half way through cleaning a data structure… Is that a good place to exit or do we need to clean up first?

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace BackgroundTasksASPNETCore.Services
{
    public class LongRunningSingleTaskService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // simulate logic by waiting for 2 seconds
            await Task.Delay(2000);
            // check if we should be exiting
            if (stoppingToken.IsCancellationRequested)
            {
                // clean up the state before exiting
                return;
            }
            // simulate more logic
            await Task.Delay(2000);
        }
    }
}

Life Time Background Tasks

The last example is a life time task, this can be great for broadcasting server updates using SignalR hubs or other items that need to run constantly with the website. The life time tasks simply loop while the cancellation isn’t requested.

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

namespace BackgroundTasksASPNETCore.Services
{
    public class LifeTimeTaskService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while(!stoppingToken.IsCancellationRequested)
            {
                // do some logic, for this example lets just wait for 2 seconds
                await Task.Delay(2000);
            }
        }
    }
}

With life time tasks we also need to be cautious that they don’t contain long running logic which might affect the shutdown of the website. Again we can monitor the state of the cancellation token at appropriate points in the code… performing any clean up before exiting.

Registering The Services

The final step to remember is registering the services within ConfigureServices in the Startup class.

public void ConfigureServices(IServiceCollection services)
        {
            // omitted for brevity 
            services.AddHostedService<ShortRunningSingleTaskService>();
            services.AddHostedService<LongRunningSingleTaskService>();
            services.AddHostedService<LifeTimeTaskService>();
        }

Conclusion

Now you’ve gained some understanding of the Background Service class and how we can use it to start and stop background services with the website.

One reply on “Background Tasks with ASP.NET Core 3.1”

Leave a Reply

Your email address will not be published. Required fields are marked *