Using SQL Server with MSMQ

Hangfire.SqlServer.MSMQ extension changes the way Hangfire handles job queues. Default implementation uses regular SQL Server tables to organize queues, and this extensions uses transactional MSMQ queues to process jobs in a more efficient way:

Feature Raw SQL Server SQL Server + MSMQ
Retry after process termination Immediate after restart Immediate after restart
Worst job fetch time Polling Interval (15 seconds by default) Immediate

So, if you want to lower background job processing latency with SQL Server storage, consider switching to using MSMQ.

Installation

MSMQ support for SQL Server job storage implementation, like other Hangfire extensions, is a NuGet package. So, you can install it using NuGet Package Manager Console window:

PM> Install-Package Hangfire.SqlServer.Msmq

Configuration

To use MSMQ queues, you should do the following steps:

  1. Create them manually on each host. Don’t forget to grant appropriate permissions. Please note that queue storage is limited to 1048576 KB by default (approximately 2 millions enqueued jobs), you can increase it through the MSMQ properties window.
  2. Register all MSMQ queues in current SqlServerStorage instance.

If you are using only default queue, call the UseMsmqQueues method just after UseSqlServerStorage method call and pass the path pattern as an argument.

GlobalConfiguration.Configuration
    .UseSqlServerStorage("<connection string or its name>")
    .UseMsmqQueues(@"FormatName:Direct=OS:localhost\hangfire-{0}");

To use multiple queues, you should pass them explicitly:

GlobalConfiguration.Configuration
    .UseSqlServerStorage("<connection string or its name>")
    .UseMsmqQueues(@"FormatName:Direct=OS:localhost\hangfire-{0}", "critical", "default");

Limitations

  • Only transactional MSMQ queues supported for reliability reasons inside ASP.NET.
  • You can not use both SQL Server Job Queue and MSMQ Job Queue implementations in the same server (see below). This limitation relates to Hangfire Server only. You can still enqueue jobs to whatever queues and watch them both in Hangfire Dashboard.

Transition to MSMQ queues

If you have a fresh installation, just use the UseMsmqQueues method. Otherwise, your system may contain unprocessed jobs in SQL Server. Since one Hangfire Server instance can not process job from different queues, you should deploy multiple instances of Hangfire Server, one listens only MSMQ queues, another – only SQL Server queues. When the latter finish its work (you can see this in Dashboard – your SQL Server queues will be removed), you can remove it safely.

If you are using default queue only, do this:

/* This server will process only SQL Server table queues, i.e. old jobs */
var oldStorage = new SqlServerStorage("<connection string or its name>");
var oldOptions = new BackgroundJobServerOptions
{
    ServerName = "OldQueueServer" // Pass this to differentiate this server from the next one
};

app.UseHangfireServer(oldOptions, oldStorage);

/* This server will process only MSMQ queues, i.e. new jobs */
GlobalConfiguration.Configuration
    .UseSqlServerStorage("<connection string or its name>")
    .UseMsmqQueues(@"FormatName:Direct=OS:localhost\hangfire-{0}");

app.UseHangfireServer();

If you use multiple queues, do this:

/* This server will process only SQL Server table queues, i.e. old jobs */
var oldStorage = new SqlServerStorage("<connection string>");
var oldOptions = new BackgroundJobServerOptions
{
    Queues = new [] { "critical", "default" }, // Include this line only if you have multiple queues
    ServerName = "OldQueueServer" // Pass this to differentiate this server from the next one
};

app.UseHangfireServer(oldOptions, oldStorage);

/* This server will process only MSMQ queues, i.e. new jobs */
GlobalConfiguration.Configuration
    .UseSqlServerStorage("<connection string or its name>")
    .UseMsmqQueues(@"FormatName:Direct=OS:localhost\hangfire-{0}", "critical", "default");

app.UseHangfireServer();

Please use Hangfire Forum for long questions or questions with source code.