What is Hangfire?
Hangfire is an open-source and well-documented task scheduler for ASP.NET and ASP.NET Core and is completely free for commercial use. It's multi-threaded, easily scalable, and offers a variety of job types. It's well-structured, simple to use, and gives a powerful performance.
Why is Hangfire used?
It is mainly used to perform background tasks such as batch/email notification, batch import of files, video/image processing, database maintaining, file purging, etc. Hangfire can be used for background tasks with high/low CPU consumption, short/long running tasks, recurring jobs, fire and forget, and many more.
Hangfire Dashboard and Database
Hangfire Dashboard, we can see all the running and scheduled jobs we create with our Hangfire client. We can also monitor servers, job retries, and failed jobs and monitor all jobs in the queue. Another great thing we can do in the Dashboard is manually trigger any existing jobs.
For storing job definitions and statuses, Hangfire can use a SQL Server database by default, and we can also choose other options.
Different Types of Jobs in Hangfire
Different types of jobs that are available in Hangfire.
- Fire-and-Forget Jobs
Fire-and-forget jobs are executed only once and almost immediately after creation.
- Delayed Jobs
Delayed jobs are executed only once, but not immediately, after a specific time interval.
- Recurring Jobs
Recurring jobs fire many times on the specified CRON schedule.
- Continuations
Continuations are executed when its parent job has been finished.
There are also two jobs available in Hangfire, but these are present in the Hangfire Pro version and used to execute multiple jobs in batch as a single entity, which are below.
- Batches
A batch is a group of background jobs created atomically and considered a single entity.
- Batch Continuations
Batch continuation is fired when all background jobs in a parent batch are finished.
Set up Hangfire in ASP.NET Core
Step 1
Let's create a new ASP.NET Core Web API project in Visual Studio 2022
Step 2
Provide the Project name HangfireDemo and then provide the location
Step 3
Provide some additional information like .NET 6, Configure for HTTPS, and enable Open API support
Step 4
Install the below NuGet packages :
- Hangfire.AspNetCore
- Hangfire.SqlServer
Step 5
Create a new API Controller named as HomeController
using Hangfire;
using Microsoft.AspNetCore.Mvc;
namespace HangfireDemo.Controllers
{
[ApiController]
public class HomeController : Controller
{
[HttpGet]
[Route("FireAndForgetJob")]
public string FireAndForgetJob()
{
//Fire - and - Forget Jobs
//Fire - and - forget jobs are executed only once and almost immediately after creation.
var jobId = BackgroundJob.Enqueue(() => Console.WriteLine("Welcome user in Fire and Forget Job Demo!"));
return $"Job ID: {jobId}. Welcome user in Fire and Forget Job Demo!";
}
[HttpGet]
[Route("DelayedJob")]
public string DelayedJob()
{
//Delayed Jobs
//Delayed jobs are executed only once too, but not immediately, after a certain time interval.
var jobId = BackgroundJob.Schedule(() => Console.WriteLine("Welcome user in Delayed Job Demo!"), TimeSpan.FromSeconds(60));
return $"Job ID: {jobId}. Welcome user in Delayed Job Demo!";
}
[HttpGet]
[Route("ContinuousJob")]
public string ContinuousJob()
{
//Fire - and - Forget Jobs
//Fire - and - forget jobs are executed only once and almost immediately after creation.
var parentjobId = BackgroundJob.Enqueue(() => Console.WriteLine("Welcome user in Fire and Forget Job Demo!"));
//Continuations
//Continuations are executed when its parent job has been finished.
BackgroundJob.ContinueJobWith(parentjobId, () => Console.WriteLine("Welcome Sachchi in Continuos Job Demo!"));
return "Welcome user in Continuos Job Demo!";
}
[HttpGet]
[Route("RecurringJob")]
public string RecurringJobs()
{
//Recurring Jobs
//Recurring jobs fire many times on the specified CRON schedule.
RecurringJob.AddOrUpdate(() => Console.WriteLine("Welcome user in Recurring Job Demo!"), Cron.Hourly);
return "Welcome user in Recurring Job Demo!";
}
[HttpGet]
[Route("BatchesJob")]
public string BatchesJob()
{
//Batches - This option is available into hangfire Pro only
//Batch is a group of background jobs that is created atomically and considered as a single entity.
//Commenting the code as it's only available into Pro version
//var batchId = BatchJob.StartNew(x =>
//{
// x.Enqueue(() => Console.WriteLine("Batch Job 1"));
// x.Enqueue(() => Console.WriteLine("Batch Job 2"));
//});
return "Welcome user in Batches Job Demo!";
}
[HttpGet]
[Route("BatchContinuationsJob")]
public string BatchContinuationsJob()
{
//Batch Continuations - This option is available into hangfire Pro only
//Batch continuation is fired when all background jobs in a parent batch finished.
//Commenting the code as it's only available into Pro version
//var batchId = BatchJob.StartNew(x =>
//{
// x.Enqueue(() => Console.WriteLine("Batch Job 1"));
// x.Enqueue(() => Console.WriteLine("Batch Job 2"));
//});
//BatchJob.ContinueBatchWith(batchId, x =>
//{
// x.Enqueue(() => Console.WriteLine("Last Job"));
//});
return "Welcome user in Batch Continuations Job Demo!";
}
}
}
Step 6
Configure things in Program.cs related to Hangfire, like SQL Server Database Connection and middleware
using Hangfire;
using Hangfire.SqlServer;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
}));
builder.Services.AddHangfireServer();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseHangfireDashboard("/dashboard");
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 7
Configure the connection string into the appsettings.json file.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Hangfire": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"HangfireConnection": "Server=DESKTOP-V06VDPI\\SQLEXPRESS;Database=Hangfire;User Id=sa;Password=sa@123;Trusted_Connection=True;Integrated Security=SSPI;"
}
}
Step 8
Now, run the application. It will open up the swagger window and show all API Endpoints we have created. We will hit the API one by one to test the things.
Also, it will create the tables in Hangfire Database related to managing the Hangfire Jobs.
Step 9
After hitting the API, you can now open the Hangfire dashboard to manage background running jobs.
Open up a new window/tab and hit the URI https://localhost:7095/dashboard
We have configured /Dashboard URI into Program.cs file, so our route is /Dashboard
If you haven't configured any route name into Program.cs file, then your Dashboard URI will be the default URI https://localhost:7095/hangfire
Now hit the API one by one and monitor the Dashboard.
The Dashboard shows all the running and scheduled jobs we created with our Hangfire client. We can also monitor servers, job retries, and failed jobs and monitor all jobs in the queue. Another great thing we can do in the Dashboard is manually trigger existing jobs.
Call Jobs through Hangfire Interface via Dependency Injection
In our API's HomeController, we have used hangfire's classes to call different Jobs like BackgroundJob and RecurringJob.
We can also use Hangfire's Interface to call different Jobs like IBackgroundJobClient and IRecurringJobManager.
Sample Code for calling different Jobs through Interface via Dependency Injection.
using Hangfire;
using Microsoft.AspNetCore.Mvc;
namespace HangfireDemo.Controllers
{
public class HangfireController : Controller
{
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly IRecurringJobManager _recurringJobManager;
public HangfireController(IBackgroundJobClient backgroundJobClient, IRecurringJobManager recurringJobManager)
{
_backgroundJobClient = backgroundJobClient;
_recurringJobManager = recurringJobManager;
}
[HttpGet]
[Route("IFireAndForgetJob")]
public string FireAndForgetJob()
{
//Fire - and - Forget Jobs
//Fire - and - forget jobs are executed only once and almost immediately after creation.
var jobId = _backgroundJobClient.Enqueue(() => Console.WriteLine("Welcome user in Fire and Forget Job Demo!"));
return $"Job ID: {jobId}. Welcome user in Fire and Forget Job Demo!";
}
[HttpGet]
[Route("IDelayedJob")]
public string DelayedJob()
{
//Delayed Jobs
//Delayed jobs are executed only once too, but not immediately, after a certain time interval.
var jobId = _backgroundJobClient.Schedule(() => Console.WriteLine("Welcome user in Delayed Job Demo!"), TimeSpan.FromSeconds(60));
return $"Job ID: {jobId}. Welcome user in Delayed Job Demo!";
}
[HttpGet]
[Route("IContinuousJob")]
public string ContinuousJob()
{
//Fire - and - Forget Jobs
//Fire - and - forget jobs are executed only once and almost immediately after creation.
var parentjobId = _backgroundJobClient.Enqueue(() => Console.WriteLine("Welcome user in Fire and Forget Job Demo!"));
//Continuations
//Continuations are executed when its parent job has been finished.
BackgroundJob.ContinueJobWith(parentjobId, () => Console.WriteLine("Welcome Sachchi in Continuos Job Demo!"));
return "Welcome user in Continuos Job Demo!";
}
[HttpGet]
[Route("IRecurringJob")]
public string RecurringJobs()
{
//Recurring Jobs
//Recurring jobs fire many times on the specified CRON schedule.
_recurringJobManager.AddOrUpdate("jobId", () => Console.WriteLine("Welcome user in Recurring Job Demo!"), Cron.Hourly);
return "Welcome user in Recurring Job Demo!";
}
}
}
Summary
In this article, we looked at Hangfire, which we have used in .NET 6 to schedule background jobs. Hoping you understand the things related to Hangfire.