HI
We are using Hangfire in an MVC web application running 3 instances behind a load balancer. To make sure the scheduled jobs dont start on each server we use the attribute
[DisableConcurrentExecution(timeoutInSeconds: 600)]
Thats all pretty nice and working.
But I wonder if it was possible solve this in a way that i could explicit tell Hangfire only to run on one specific server? Like the name of the server.
Yes … Make your own Queue type attribute.
i.e.
public class MachineQueueAttribute : JobFilterAttribute, IElectStateFilter
{
public void OnStateElection(ElectStateContext context)
{
if (!(context.CandidateState is EnqueuedState enqueuedState)) return;
var q = string.Concat(System.Environment.MachineName.ToLowerInvariant()
.Where(char.IsLetterOrDigit));
enqueuedState.Queue = q;
}
}
And then use that attribute in your job run method for instance i.e.
[MachineQueue]
public string Run(PerformContext context)
{
/// code here
}
Of course you would also need to subscribe to that Queue when setting up the appserver i.e.
var q = string.Concat(Environment.MachineName.ToLowerInvariant()
.Where(char.IsLetterOrDigit));
_options = new BackgroundJobServerOptions
{
Queues = new[]
{
q
}
};
_server = new BackgroundJobServer(_options);
The little bit with the IsLetterOrDigit is to ensure only valid characters are kept for the queue name (since server names can contain hyphens for instance and Queue names in HangFire cannot. Also needs to be lowercase.
Note that this is just the code for the general idea. In my case I needed a way to queue a series (a chain) of jobs on the same server as the one where the fire and forget jobs were created.
You can also hard code the queues with the [Queue()] attribute but that is a hardcoded name so not very flexible for most cases
@Hans_Engelen
When does the OnStateElection happen? I am trying to find other ways of manipulating the queues.
Between the different state transitions which is why the sample code I gave checks if the Candidate State is an EnqueuedState. There is no point after all in changing the queue after the job has finished processing for example.
Thanks Hans. In Jeppe_Svendsen’s solution, wouldn’t he want to change the queue name in Enqueued state?
Ideally just before it transitions to Enqueued really. Which is what I have in the code sample. That, as I understand it, is where the OnStateElection happens in between the transition of states as opposed to during a particular state. The reason being of course that in a multi threaded environment changing it while the state is already ‘Enqueued’ might be too late. The job could already have changed states again (i.e started processing).
Again this is how I understand it.