Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

hangfire

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?

like image 894
Tony_Henrich Avatar asked Feb 02 '17 21:02

Tony_Henrich


People also ask

How do I run a Hangfire job?

Hangfire handles different types of background jobs, and all of them are invoked in a separate execution context. Fire and forget jobs are executed once on an immediate basis after creation. Once you create a fire-and-forget job, it is saved to its queue ("default" by default, but multiple queues supported).

How do I stop a recurring job on Hangfire?

You can remove an existing recurring job by calling the RemoveIfExists method. It does not throw an exception when there is no such recurring job.

Is Hangfire scalable?

Hangfire is an open-source and well-documented task scheduler for ASP.NET and ASP.NET Core. It's multi-threaded, easily scalable, and offers a variety of job types.

How does Hangfire Server work?

Hangfire Server consists of different components that are doing different work: workers listen to queue and process jobs, recurring scheduler enqueues recurring jobs, schedule poller enqueues delayed jobs, expire manager removes obsolete jobs and keeps the storage as clean as possible, etc.


1 Answers

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);
        }
    }
}
like image 123
GôTô Avatar answered Jan 01 '23 02:01

GôTô