Multiple Background Job Servers with different MSMQ Queues

Tags: #<Tag:0x00007f06612d8c78>

Hey Folks,

I’ve got a Hangfire site setup using MSMQ + SQL Server and I’ve either found a bug or got a configuration issue as 10-20% of the time when I enqueue a Job, it ends up in the SQL Server queue instead of the MSMQ.

My website has got 3 Background Job Servers:

  1. Runs against “default” queue, has 1 worker
  2. Runs against “housekeeping” queue, has 8 workers
  3. Runs multiple IBackgroundProcess, has 1 worker, don’t want it to process messages from any queues

In my Hangfire Boostrapper code, I’ve got the following:

GlobalConfiguration.Configuration
.UseSqlServerStorage(assrConnectionString, new SqlServerStorageOptions
{
    PrepareSchemaIfNecessary = false
})
.UseMsmqQueues(MsmqTransactionType.Dtc, hangfireQueuePattern, "housekeeping", "default");

_changeMessageBackgroundJobServer = new BackgroundJobServer(new BackgroundJobServerOptions
{
    WorkerCount = 1, 
    Queues = new [] {"default"}
});

_housekeepingBackgroundJobServer  = new BackgroundJobServer(new BackgroundJobServerOptions
{
    WorkerCount = 8,
    Queues = new[] { "housekeeping" }
});

var options = new BackgroundJobServerOptions
{
    WorkerCount = 1,
    Queues = new[] {"default"} 
};
var storage = new SqlServerStorage(assrConnectionString);
var backgroundProcesses = new List<IBackgroundProcess>(// some background processes in here);
_backgroundProcessServer = new BackgroundJobServer(options, storage, backgroundProcesses);

I run my Recurring Job like:
RecurringJob.AddOrUpdate<Tasks>("RecurringTask", j => j.TaskA(), "*/5 * * * *");

And my Jobs look like:

    [Queue("housekeeping")]
    public class Tasks
    {
        public void TaskA()
        {
            foreach(var w in GetWork())
            {
                BackgroundJob.Enqueue<Tasks>(j => j.TaskB(w));
            }
        }

        public void TaskB(Work w)
        {
           // 20% of the time this method ends up in the Sql "housekeeping" queue instead of the MSMQ "housekeeping" queue
        }
    }

This is probably a configuration issue but I really can’t see what I need to do differently.

Thanks in advance for the help!

I found a solution, but I still don’t know why Jobs would end up in SQL Storage Queue instead of MSMQ.

For the _backgroundProcessServer, changing it’s constructor to use JobStorage.Current seemed to have solved the problem (rather than newing up a new SqlServerStorage). The weird part for me is that server should never have been processing any of the “housekeeping” messages anyway…so that’s till not solved.

Here’s the code that I changed:

_backgroundProcessServer = new BackgroundJobServer(new BackgroundJobServerOptions
    {
        WorkerCount = 1,
        Queues = new[] { "default" }
    }, JobStorage.Current, backgroundProcesses);