We needed a simple solution to run recurring jobs for our user group web site. WebJobs in Azure sounded like the perfect solution, but unfortunately they do not work with App Services on Linux. We needed another approach and we found a much better solution with Background Tasks. All we need to do is to implement the two interfaces IHostedService and IDisposable, and the worker runs outside of the requests to our application.
Create your background task
In the official documentation you find a fully functional example that we slightly modified for this post. There are three main methods we need to look at:
- StartAsync() sets everything up for our background task. Here we can set the interval in which our task should run.
- StopAsync() makes sure that the background task performs a graceful shutdown.
- DoWork() is where we put our logic in.
In this example our background task should run every 5 seconds and log to the console:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public class TimedHostedService : IHostedService, IDisposable { private int executionCount = 0; private readonly ILogger<TimedHostedService> _logger; private Timer? _timer = null; public TimedHostedService(ILogger<TimedHostedService> logger) { _logger = logger; } public Task StartAsync(CancellationToken stoppingToken) { _logger.LogInformation("Timed Hosted Service running."); _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); return Task.CompletedTask; } private void DoWork(object? state) { var count = Interlocked.Increment(ref executionCount); _logger.LogInformation( "Timed Hosted Service is working. Count: {Count}", count); } public Task StopAsync(CancellationToken stoppingToken) { _logger.LogInformation("Timed Hosted Service is stopping."); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } } |
Configure the background task
The background task uses the same dependency injection module as the rest of the ASP.NET Core application. If you need a dependency, you inject it through the constructor.
We can add the background task itself to the services list as we do it with the other dependencies:
1 2 |
var builder = WebApplication.CreateBuilder(args); builder.Services.AddHostedService<TimedHostedService>(); |
This is all you need to do for the application to find the background task.
Run the background task
The background task starts automatically when we start our web application. We can see its log messages in the console:
info: TimedHostedService[0]
Timed Hosted Service is working. Count: 1
info: TimedHostedService[0]
Timed Hosted Service is working. Count: 2
info: TimedHostedService[0]
Timed Hosted Service is working. Count: 3
info: TimedHostedService[0]
Timed Hosted Service is working. Count: 4
info: TimedHostedService[0]
Timed Hosted Service is working. Count: 5
Conclusion
Running recurring tasks outside the web request thread is very useful for maintenance tasks and long-running operations. This way we can prepare and clean up everything without the users experiencing a slow response.