如何让Hangfire实例只运行自己的工作?

时间:2017-02-02 21:08:56

标签: hangfire

我在使用相同数据库的两台服务器上运行了几个Hangfire实例。每个实例根据基于服务器名称的某些条件提交要运行的作业,以便没有两个实例运行相同的作业。我注意到他们正在运行相同的工作,这意味着当一个实例运行它时,无论是否提交了工作,它都会在数据库中挑选队列中的任何工作。我认为在最新版本1.6.x中,每项工作都是独一无二的。这似乎并不意味着它只在创建它的实例上运行?

如何让每个实例只运行它提交的作业?

1 个答案:

答案 0 :(得分:2)

您需要使用队列来选择处理特定作业的服务器。

我们的想法是通过指定队列对作业进行分类。然后,对于每个服务器,您将指定他们观察的队列。

在我看来,唯一的问题是为工作选择队列并不简单(除非你正在使用RecurringJobs)。

服务器配置

当您启动服务器的Hangfire实例时,请按照the documentation使用Queues BackgroundJobServerOptions

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

选择作业队列

有两种情况:

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

  2. BackgroundJobs:您无法在入队时间(Hangfire.BackgroundJob.Enqueue(() => myClass.myMethod());)指定作业的队列,因此没有选项。解决方案是使用方法或类属性。 Hangfire提供QueueAttribute
    [Queue("myqueueformyserver")] public void myMethod() { }

  3. 如果我了解您的要求,静态QueueAttribute将不适合您,因为您想要动态分配队列。我有同样的情况,并根据code of the QueueAttribute创建了我自己的属性。

    它看起来像那样(适应你的意愿/需要)

    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);
            }
        }
    }