Optimizing Background Processing with HangFire in .NET
Overview
Scheduling and monitoring background tasks is challenging work. Every big application needs to implement background tasks to accomplish background work, such as data processing, email reminders, SMS queues, and email queues. Windows Service is the most typical approach to meet the necessity.
Hangfire is an open-source library that schedules and executes background jobs in .NET applications. You'll be able to create a simple background process inside the same application pool or thread without creating separate applications. Hangfire creates background jobs in persistence storage, like MS SQL Server, Redis, MongoDB, and others, that may prevent you from losing the job of recycling IIS pools or exception prevalence.
What is Hangfire?
Hangfire provides an easy-to-use framework for managing background jobs. It's designed to run tasks outside the request-response lifecycle, freeing your application to handle critical business logic without being blocked by time-consuming operations.
Hangfire lets you kick off method calls outside of the request processing pipeline in an effortless, but reliable way. These method invocations are performed in a background thread and called background jobs.
Key Features:
No Windows Service Required: Works as part of your .NET application.
Dashboard: Provides a real-time dashboard for monitoring jobs.
Scalable: Works with various storage providers like SQL Server, Redis, and others.
Supports ASP.NET Core and .NET Framework: A versatile choice for modern and legacy applications.
library consists of three main components: client, storage, and server. Here is a small diagram that describes the main processes in Hangfire:
Client
You can create any kind of background jobs using Hangfire:
Types of Hangfire Jobs
Hangfire supports four primary types of jobs:
1. Fire-and-Forget Jobs
These jobs run only once and are triggered immediately after creation. They're ideal for tasks like sending emails, processing user uploads, or logging activity.
Example:
public void SendEmail(string userEmail)
{
BackgroundJob.Enqueue(() => EmailService.SendWelcomeEmail(userEmail));
}
2. Delayed Jobs
Delayed jobs are executed once, but only after a specified time delay. Use them for tasks that shouldn't run immediately, like sending follow-up notifications.
Example:
public void SendDelayedNotification(string userEmail)
{
BackgroundJob.Schedule(() => NotificationService.SendReminderEmail(userEmail), TimeSpan.FromDays(1));
}
3. Recurring Jobs
Recurring jobs are executed repeatedly based on a schedule. This is perfect for tasks like database cleanup, sending daily reports, or running periodic maintenance.
Example:
RecurringJob.AddOrUpdate("daily-reports",
() => ReportService.GenerateDailyReport(), Cron.Daily);
Hangfire uses CRON expressions to define recurring schedules.
4. Continuation Jobs
Continuation jobs run only after a parent job completes. This is useful for workflows where subsequent tasks depend on the success of the previous one.
Example:
var parentJobId = BackgroundJob.Enqueue(() => JobService.ProcessData());
BackgroundJob.ContinueWith(parentJobId, () => JobService.GenerateReport());
Storage
Hangfire keeps background jobs and other information that relates to the processing inside a persistent storage. Persistence helps background jobs to survive on application restarts, server reboots, etc. This is the main distinction between performing background jobs using CLR’s Thread Pool and Hangfire. Different storage backends are supported:
SQL Azure, SQL Server 2008 R2 (and later of any edition, including Express)
GlobalConfiguration.Configuration.UseSqlServerStorage("db_connection");
Setting Up Hangfire in ASP.NET Core
Here’s how you can integrate Hangfire into your ASP.NET Core application:
Step 1: Install Hangfire
Install Hangfire and its SQL Server storage provider (or another storage of your choice):
dotnet add package Hangfire
dotnet add package Hangfire.SqlServer
Step 2: Configure Hangfire
Add Hangfire to your Startup.cs
or Program.cs
file:
builder.Services.AddHangfire(config =>
config.UseSqlServerStorage("YourConnectionString"));
builder.Services.AddHangfireServer();
Step 3: Use the Hangfire Dashboard
Enable the dashboard for real-time monitoring:
app.UseHangfireDashboard("/hangfire");
Best Practices for Hangfire Jobs
Use Dependency Injection: Ensure your services used in jobs are registered in the DI container to avoid dependency issues.
BackgroundJob.Enqueue<IEmailService>(service => service.SendWelcomeEmail(userEmail));
Optimize Job Payloads: Pass minimal data to jobs, preferably IDs, to reduce overhead. Retrieve full data within the job itself.
Monitor Jobs Regularly: Use the dashboard to keep track of failed jobs, execution times, and retries.
Leverage Retry Policies: Hangfire automatically retries jobs on failure. Customize this behavior for specific jobs if needed.
Secure the Dashboard: Protect the dashboard with authentication to prevent unauthorized access.
app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new MyAuthorizationFilter() } });
Common Use Cases for Hangfire
Email Notifications: Send emails asynchronously without blocking the user experience.
Data Processing: Offload heavy tasks like file uploads or image processing.
Scheduled Reports: Automate daily, weekly, or monthly reports.
Cache Updates: Refresh cached data periodically to keep it fresh.
Database Maintenance: Clean up old records or archive logs.
Conclusion
Hangfire is a versatile library that can simplify background task management in your .NET applications. Its intuitive API, powerful dashboard, and scalability make it an excellent choice for developers. By understanding the different types of jobs and following best practices, you can unlock the full potential of Hangfire to streamline your workflows.