Using Hangfire to run background jobs in .NET Core
In every system there is going to be a requirement for some asynchronous background process at some point, there is just no way around it. Fortunately dotnet core comes with a native support for background processes with the use of IHostedService
which is pretty straightforward to implement.
However I find that approach a bit lacking when compared to tools like Quartz and Hangfire that has been around for a good while, especially for when it comes to time triggered jobs you have to play around a bit with the native approach while the other 2 have it easy to configure.
I am a big fan of Hangfire and used it across a set of projects with no issues whatsoever so we are going to cover it in this post.
Getting started with Hangfire is pretty straightforward, however there is a catch you will need a relational database however that is most often not a problem and we are using some form of database behind the scenes. Let’s get started with the implementation:
Add the required NuGet packages
Add the installer that we are going to use in the Program.cs, alternatively you can add this code to the DI container setup directly
Inside the Program.cs you will want to wire everything up in the following way:
And with that you are basically done with a bare minimum configuration to run background jobs in dotnet core.
Considerations when working with Hangfire
In the above example we have configured our component to be in the role of a HangfireServer, while this is valid in the context of lightweight jobs if you consider having some hardcore processing in the background it would be way better to offload that work to a separate component, for example a console application. This way your “main” component will not be overloaded whenever the time to execute the job comes.
Access to Hangfire dashboard is another issue we need to tackle. Since there might be sensitive data shown in the dashboard by default it is only available in the local and/or development environments (basically having the specific environment variable set to development). If you want to expose it inside your production services we will need to configure an Authorization Filter, there are a bunch of flavors to Authorization and I can’t cover them all so as part of the workshop below you will find the example skeleton code you will need to set up the filter:
And then in the startup wire it all up like this:
Running Hangfire in a centralized setup
While the default approach to setting up background processing is to setup Hangfire inside the solution there is one more method that I met at some point in my career : External Hangfire API.
The general idea is to have a dotnet core component where you setup Hangfire and let that component call the other ones via HTTP requests. The other components would define HTTP API endpoints to trigger a background job which would get called by the Hangfire component.
There are some benefits and downsides as well to this approach.
Benefits:
Centralized component where you can check ALL the background processes inside your system.
You don’t need to setup Hangfire in each and every component, you just define the endpoint with a specific job.
Downsides:
HTTP Request timeout. While this can be easily mitigated via a form of Pub-Sub where the Hangfire component would send a message to a queue, this is still an issue that needs to be tackled, and pub-sub would introduce other issues as well.
Monitoring the progress of a job becomes really difficult.
Single point of failure for the background processes.
What to watch/read next?
Below you will find links to 3 series covering Integration testing in .NET, Minimal API’s and building a Modular monolith from beginner to advanced level.
Integration testing - from ground zero series