As applications grow and evolve, the need for background tasks and scheduled jobs becomes more of a necessity. This is especially true with microservice architectures and in dealing with eventual consistency and event-driven communication. .Net Core 2.0 has a new interface, IHostedService, which makes executing background jobs easier. When using the IHostedService interface you can register multiple hosted services that will run in the background of your web application.

The IHostedService interface looks like:

You may be thinking, “What’s the difference between a hosted service implementing IHostedService vs starting a background thread to run a task?” The difference is the hosted service will be started and stopped with the application. When starting a background thread, the thread cannot gracefully handle clean-up actions and will be killed when the application is stopped. The HostedServiceExecutor will handle the starting and stopping of the hosted services. This will allow for the hosted services to be cleaned up gracefully when the application is stopped.

When creating a hosted service, you could implement the IHostedService, but .NET Core 2.1 will include an abstract base class called BackgroundService. The BackgroundService will provide the common operations needed for background tasks such as cancellation tokens. If you are still on .NET 2.0, you can copy this base class into your repository. The code for the BackgroundService class is below.

Creating a Hosted Service:

A use case for a background task is having a task that “polls” a database to check for updates. When dealing with microservices, you might need to have local caches for some services. Local caches will contain copies of data from other services. This helps avoid chained API calls and dependencies on other microservices. One approach to keep the cache up to date is having clients subscribe to events that an application publishes (pub/sub). Another approach is having the applications journal the events (write the events to a database), and then the clients poll that journal database for new events. At AppRiver, the latter approach has proven to be a good fit when dealing with local cache synchronization. Below is an example of a hosted service polling a journaling database:

To keep this hosted service example simple, all of the logic around polling and updating the database is abstracted away in the JournalingUpdateService.

Once the application starts, the HostedServiceExecutor will kick off all the IHostedServices registered in the dependency injection in the Startup class (more on DI later). The JournalingManagerService’s ExecuteAsync method will be called. This will call the Update method on the JournalingUpdateService and then it will wait for 3 seconds before repeating. The service will continue to run until the token is canceled / application is stopped. The BackgroundService handles a lot of the work around service lives and if you are interested in more information on that, check out this blog post about the HostedService class.

The last part involves wiring up the hosted services. Each IHostedService will need registering (using dependency injection) in the ConfigureServices method in the Startup class (Note: multiple hosted services can be registered). This will look something like this:

Summary

The IHostedService interface is an easy way to run background tasks with a web application or host. Its main benefit is how gracefully it handles the clean up when the application is stopping. I would warn against overusing this feature and running a large number of tasks.

I’d recommend trying out the IHostedService interface and thinking about where it can be used in your architecture.

I’ve put together a sample repository to try out a hosted service. This repository uses an asynchronous messaging framework to journal integration events to a database. There are two microservices, Billing.API and Customer.API. The Billing.API keeps a local cache of the customer’s name. When the Customer.API updates the customer name it will publish an event to the journaling database. The Billing.API has a hosted service called JournalingManagerService which will poll the journaling database every three seconds to check for updated events.

Additional Resources

Leave a Comment