How to make a Hangfire instance run its own jobs only?
Asked Answered
E

1

7

I have a couple instances of Hangfire running on two servers using the same database. Each instance submits jobs to be run based on some criteria based on server name so that no two instances run the same job. I noticed that they are running the same jobs which means when an instance is running it's picking any job in the queue in the database regardless if it submitted the job or not. I thought in the latest version 1.6.x, each job is unique. It seems this doesn't mean it runs only on the instance that created it?

How do I get each instance to run jobs it submitted only?

Eelworm answered 2/2, 2017 at 21:8 Comment(1)
Did my answer help at all?Dickinson
U
10

You need to use queues to select which server handles specific jobs.

The idea is to categorize jobs by specifying a queue. Then for each server you will specify which queue(s) they watch.

The only problem with this, in my opinion, is that choosing the queue for a job is not straightforward (unless you are working with RecurringJobs).

Server Configuration

When you start the Hangfire instance for a server, use the Queues BackgroundJobServerOptions as per the documentation:

app.UseHangfireServer(new BackgroundJobServerOptions()
    {
        // order defines priority
        // beware that queue names should be lowercase only
        Queues = new [] { "critical", "default", "myqueueformyserver" } 
    });

Selecting a queue for a job

There are two cases:

  1. RecurringJobs: RecurringJob.AddOrUpdate("MyFirstRecurringJob", () => myClass.myMethod(), Cron.Minutely(), null, "myqueueformyserver");

  2. BackgroundJobs: you cannot specify the queue for the job at enqueue time (Hangfire.BackgroundJob.Enqueue(() => myClass.myMethod());) there is no option for this. The solution is to use a method or class attribute. Hangfire provides a QueueAttribute:
    [Queue("myqueueformyserver")] public void myMethod() { }

If I understand your requirements, the static QueueAttribute will not fit you as you want to dynamically assign the queue. I had the same situation and created my own attribute inspired by the code of the QueueAttribute.

It looks something like that (adapt to your willing/needs)

public class MyQueueAttribute : JobFilterAttribute, IElectStateFilter
{
    public MyQueueAttribute(string paramQueue)
    {
        ParamQueue = paramQueue;
    }

    public string ParamQueue { get; }

    public void OnStateElection(ElectStateContext context)
    {
        var enqueuedState = context.CandidateState as EnqueuedState;
        if (enqueuedState != null)
        {
            enqueuedState.Queue = string.Concat(Environment.MachineName.ToLower(), 
                                                ParamQueue);
        }
    }
}
Unbalanced answered 3/2, 2017 at 8:40 Comment(4)
Yeah thanks. I was testing it yesterday. It seems the attribute doesn't help. Looks like it's a bug. Someone mentioned the same issue in the comments on Hangfire's site.. Using queue name in the method seems to work better... so far.Eelworm
@Unbalanced Are you really sure this approach is working? I have 1 db and multiple applications which one hangfire servers running on each applications and the arranged the queue names as per application names so they are unique. After i register a recurring job it is being called by the application which registered on the first time but after that the other application is trying to fetch the job so the generic reflection error occurs. What im expecting is every hangfire server on every application should only try to fetch the jobs with the queue names matching on their own.Wendelina
Have you added the attribute to the methods?Dickinson
For case 2 (BackgroundJobs), you can do this: var hangfireClient = new BackgroundJobClient(); hangfireClient.Create(() => myClass.myMethod(), new Hangfire.States.EnqueuedState("myqueueformyserver"));Stanwood

© 2022 - 2024 — McMap. All rights reserved.