Hangfire Configuration
MassTransit supports Hangfire as a message scheduler, providing reliable scheduled message delivery with a persistent storage backend. Hangfire is particularly useful when you need:
- Reliable scheduled message delivery that survives application restarts
- A built-in dashboard to monitor scheduled jobs
- Integration with an existing Hangfire installation in your application
- Support for recurring jobs using cron expressions
Installation
Section titled “Installation”Install the required packages:
dotnet add package MassTransit.HangfireAutomatically adds
Hangfire.Core.
You’ll also need a Hangfire storage package based on your chosen backend:
# Choose one of the following:dotnet add package Hangfire.SqlServer # SQL Serverdotnet add package Hangfire.Redis.StackExchange # Redisdotnet add package Hangfire.PostgreSQL # PostgreSQLConfigure Hangfire Storage
Section titled “Configure Hangfire Storage”Hangfire requires persistent storage to survive application restarts. Choose your storage backend:
In-Memory (Development)
Section titled “In-Memory (Development)”services.AddHangfire(h =>{ h.UseRecommendedSerializerSettings(); h.UseMemoryStorage();});SQL Server
Section titled “SQL Server”services.AddHangfire(h =>{ h.UseRecommendedSerializerSettings(); h.UseSqlServerStorage("Server=.;Database=Hangfire;");});services.AddHangfire(h =>{ h.UseRecommendedSerializerSettings(); h.UseRedisStorage("localhost:6379");});PostgreSQL
Section titled “PostgreSQL”services.AddHangfire(h =>{ h.UseRecommendedSerializerSettings(); h.UsePostgreSqlStorage(options => { options.UseNpgsqlConnection("Host=localhost;Database=hangfire;Username=postgres;Password=password"); });});Configure MassTransit
Section titled “Configure MassTransit”Configure MassTransit to use Hangfire as the message scheduler:
services.AddMassTransit(x =>{ x.AddPublishMessageScheduler();
x.AddHangfireConsumers();
x.UsingRabbitMq((context, cfg) => { cfg.UsePublishMessageScheduler();
cfg.ConfigureEndpoints(context); });});The key components are:
AddPublishMessageScheduler()- Registers the message scheduler in the containerAddHangfireConsumers()- Adds the Hangfire consumers that handle scheduling operationsUsePublishMessageScheduler()- Configures the transport to use the scheduler
Using the Message Scheduler
Section titled “Using the Message Scheduler”From a Consumer
Section titled “From a Consumer”Inject ConsumeContext and use the scheduling methods:
public class OrderProcessingConsumer : IConsumer<ProcessOrder>{ public async Task Consume(ConsumeContext<ProcessOrder> context) { // Schedule a message to be sent after a delay await context.ScheduleSend<SendNotification>( DateTime.UtcNow + TimeSpan.FromHours(1), new NotificationMessage { OrderId = context.Message.OrderId, Message = "Your order has been processed" }); }}From a Service/Controller
Section titled “From a Service/Controller”Inject IMessageScheduler from the container:
public class NotificationService{ private readonly IMessageScheduler _scheduler;
public NotificationService(IMessageScheduler scheduler) { _scheduler = scheduler; }
public async Task SendDelayedNotification(string email, string message) { await _scheduler.SchedulePublish( DateTime.UtcNow.AddDays(1), new NotificationMessage { Email = email, Message = message }); }}ScheduleSend vs SchedulePublish
Section titled “ScheduleSend vs SchedulePublish”ScheduleSend- Sends directly to a specific endpoint (useful for targeting a specific queue)SchedulePublish- Publishes to the message bus (useful for pub/sub scenarios)
// Send to a specific endpointawait context.ScheduleSend( new Uri("queue:notification-service"), delay, message);
// Publish for subscribersawait context.SchedulePublish(delay, message);Recurring Messages
Section titled “Recurring Messages”Hangfire supports recurring jobs using cron expressions:
public class DailyReportSchedule : DefaultRecurringSchedule{ public DailyReportSchedule() { ScheduleId = "daily-report"; CronExpression = "0 0 9 * * ?"; // Every day at 9 AM }}
public record GenerateDailyReport;To schedule a recurring message:
public class ReportSchedulerService{ private readonly IRecurringMessageScheduler _scheduler;
public ReportSchedulerService(IRecurringMessageScheduler scheduler) { _scheduler = scheduler; }
public async Task ScheduleDailyReports() { var inputAddress = new Uri("queue:report-generator");
await _scheduler.ScheduleRecurringSend( inputAddress, new DailyReportSchedule(), new GenerateDailyReport()); }}To cancel a recurring schedule:
await _scheduler.CancelScheduledRecurringMessage("daily-report", null);Hangfire Dashboard
Section titled “Hangfire Dashboard”To expose the Hangfire dashboard in your ASP.NET Core application:
// In Program.csvar app = builder.Build();
app.UseHangfireDashboard();
app.MapHealthChecks("/health");Securing the Dashboard
Section titled “Securing the Dashboard”In production, you should secure the dashboard:
app.UseHangfireDashboard("/hangfire", new DashboardOptions{ Authorization = new[] { new HangfireAuthFilter() }});public class HangfireAuthFilter : IDashboardAuthorizationFilter{ public bool Authorize(DashboardContext context) { // Implement your authorization logic return context.GetHttpContext().User.Identity?.IsAuthenticated == true; }}Dashboard with Base Path
Section titled “Dashboard with Base Path”If your app is hosted at a base path:
app.UseHangfireDashboard("/myapp/hangfire");Scheduled Redelivery
Section titled “Scheduled Redelivery”Hangfire can be used for scheduled message redelivery (second-level retries):
services.AddMassTransit(x =>{ x.AddConsumer<OrderProcessingConsumer>();
x.AddConfigureEndpointsCallback((context, name, cfg) => { cfg.UseScheduledRedelivery(r => r .Intervals( TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
cfg.UseMessageRetry(r => r.Immediate(3)); });
x.UsingRabbitMq((context, cfg) => { cfg.UsePublishMessageScheduler(); cfg.ConfigureEndpoints(context); });});Full ASP.NET Core Example
Section titled “Full ASP.NET Core Example”var builder = WebApplication.CreateBuilder(args);
// Configure Hangfire with SQL Server storagebuilder.Services.AddHangfire(h => h .UseRecommendedSerializerSettings() .UseSqlServerStorage(builder.Configuration.GetConnectionString("Hangfire")));
builder.Services.AddHangfireServer();
// Add MassTransit with Hangfirebuilder.Services.AddMassTransit(x =>{ x.AddPublishMessageScheduler(); x.AddConsumers(typeof(Program).Assembly); x.AddHangfireConsumers();
x.UsingRabbitMq((context, cfg) => { cfg.Host(builder.Configuration.GetConnectionString("RabbitMq"));
cfg.UsePublishMessageScheduler(); cfg.ConfigureEndpoints(context); });});
var app = builder.Build();
// Enable Hangfire Dashboardapp.UseHangfireDashboard("/hangfire", new DashboardOptions{ Authorization = new[] { new HangfireAuthFilter() }});
app.UseHealthChecks("/health");
app.Run();Samples
Section titled “Samples”- Sample-Hangfire - Official MassTransit Hangfire sample