BackgroundJob.Schedule does not run on specific queue

queues
Tags: #<Tag:0x00007f6a0576eca8>

#1

We are using Hangfire in a multi-tenant environment and are trying to separate jobs into queues per tenant, but have run into an issue with Schedule.

We have created a custom dynamic queue attribute that sets the queue based on a current application setting. This works perfectly for a regular Enqueue, but as far as I can see BackgroundJob.Schedule runs on a random queue instead of the queue of the scheduled function. No queue state seems to be saved for a scheduled job in the database.

Since any server can pick up a scheduled job it gets enqueued in the queue of whatever server picked up the job. Do we have any way at all to work around this, or do we need hangfire to support this feature for our use-case to be possible?


#2

We have found a possible solution using JobFilterAttribute by saving the queue in a table during OnStateElection in the ScheduledState, and then loading it from db during EnqueuedState.


#3

I have this exact problem.


#4

I tried a number of things and the simplest approach I could come up with was to simply wrap the job that was getting scheduled in another job that would then dispatch the original job at the appropriate time. Calling BackgroundJob.Enqueue does respect the queue if set via the Queue attribute, but Schedule does not for whatever reason. My wrapper job then sits in the default queue, waiting for its scheduled time to arrive, at which point it will get executed and the original job gets enqueued directly, at which point it will go into the correct queue by virtue of the attribute being present. My setup involves messages getting processed by handlers, so my wrapper job has two inputs - the message and the type of handler to execute, and then it performs a IBackgroundJobClient.Create(methodCall, state) based on that information.


#5

@ecs, Could you please share your solution, so we can try it on our environment?

Thank you!


#6

The following gist contains the attribute class. You have to handle storage yourself to make it work.


#7

This solution also works when you need to schedule task into specific queue with IBackgroundJobClient.Schedule:


jobId = _backgroundJobClient.Schedule(task => task.DoWork(corrId, null), TimeSpan.FromSeconds(10));
var taskState = new EnqueuedState(“test-queue”);
_backgroundJobClient.ChangeState(jobId, taskState);