Background Jobs with Hangfire
Schedule and execute background jobs reliably with Hangfire.
By EMEPublished: February 20, 2025
hangfirebackground jobsschedulingreliable execution
A Simple Analogy
Hangfire is like a personal task scheduler. It remembers your tasks, executes them even if the app restarts, and retries if something goes wrong.
Why Background Jobs?
- Non-blocking: Don't wait for long operations
- Reliable: Retry on failure
- Scheduled: Run at specific times
- Monitoring: Track job status
- Scalable: Distribute across workers
Setup
// Install NuGet package
// Install-Package Hangfire.AspNetCore
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection")));
builder.Services.AddHangfireServer();
var app = builder.Build();
app.UseHangfireDashboard("/hangfire");
app.UseHangfireServer();
Fire and Forget Jobs
public class EmailService
{
private readonly ILogger<EmailService> _logger;
public void SendEmail(string email, string subject, string body)
{
_logger.LogInformation("Sending email to {Email}", email);
Thread.Sleep(2000); // Simulate slow operation
_logger.LogInformation("Email sent successfully");
}
}
// Enqueue job
var client = new BackgroundJobClient();
client.Enqueue<EmailService>(x => x.SendEmail(
"user@example.com",
"Welcome!",
"Welcome to our service"));
// Response returned immediately
Scheduled Jobs
public class ReportService
{
public void GenerateDailyReport(string date)
{
Console.WriteLine($"Generating report for {date}");
// Expensive operation
}
}
// Schedule for later
var client = new BackgroundJobClient();
client.Schedule<ReportService>(
x => x.GenerateDailyReport(DateTime.Now.ToString("yyyy-MM-dd")),
TimeSpan.FromMinutes(10));
// Or specific time
client.Schedule<ReportService>(
x => x.GenerateDailyReport("2025-02-20"),
new DateTimeOffset(2025, 2, 20, 6, 0, 0, TimeSpan.Zero));
Recurring Jobs
// In Startup or Program.cs
var recurringJobManager = new RecurringJobManager();
// Daily job
recurringJobManager.AddOrUpdate(
"daily-cleanup",
() => new CleanupService().DeleteOldFiles(),
Cron.Daily(6) // Every day at 6 AM
);
// Every 5 minutes
recurringJobManager.AddOrUpdate(
"health-check",
() => new HealthCheckService().Check(),
Cron.MinuteInterval(5)
);
// Custom cron
recurringJobManager.AddOrUpdate(
"weekly-report",
() => new ReportService().Generate(),
"0 6 ? * MON" // 6 AM every Monday
);
// Remove job
recurringJobManager.RemoveIfExists("daily-cleanup");
Retry Policies
client.Enqueue<DataService>(x => x.ImportData(file),
new EnqueuedState { Reason = "Manual enqueue" });
// Automatic retries configured in Hangfire options
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connectionString)
.WithJobExpirationTimeout(TimeSpan.FromDays(7))
);
// In job method - manual retry
public void ProcessWithRetry(string data)
{
try
{
ProcessData(data);
}
catch (Exception ex)
{
throw new InvalidOperationException("Retry", ex);
}
}
Job Progress and Cancellation
public class LongRunningService
{
public void ProcessLargeDataset(string id, IJobCancellationToken token)
{
var items = GetItems(id);
foreach (var item in items)
{
if (token.ShutdownToken.IsCancellationRequested)
break;
ProcessItem(item);
token.ThrowIfCancellationRequested();
}
}
}
// Client enqueue
var jobId = BackgroundJob.Enqueue<LongRunningService>(
x => x.ProcessLargeDataset("data-123", JobCancellationToken.Null));
// Monitor progress via dashboard
Best Practices
- Make jobs idempotent: Safe to run multiple times
- Log heavily: Track job execution
- Set timeouts: Prevent hanging jobs
- Monitor dashboard: Check job health
- Use persistent storage: SQL Server or Redis
Related Concepts
- Job queues
- Distributed processing
- Cron scheduling
- Async task processing
Summary
Hangfire provides reliable, persistent background job execution with retry logic, scheduling, and monitoring. Use it for async tasks that shouldn't block user requests.