我在使用相同数据库的两台服务器上运行了几个Hangfire实例。每个实例根据基于服务器名称的某些条件提交要运行的作业,以便没有两个实例运行相同的作业。我注意到他们正在运行相同的工作,这意味着当一个实例运行它时,无论是否提交了工作,它都会在数据库中挑选队列中的任何工作。我认为在最新版本1.6.x中,每项工作都是独一无二的。这似乎并不意味着它只在创建它的实例上运行?
如何让每个实例只运行它提交的作业?
答案 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" }
});
有两种情况:
RecurringJobs:RecurringJob.AddOrUpdate("MyFirstRecurringJob", () => myClass.myMethod(), Cron.Minutely(), null, "myqueueformyserver");
BackgroundJobs:您无法在入队时间(Hangfire.BackgroundJob.Enqueue(() => myClass.myMethod());
)指定作业的队列,因此没有选项。解决方案是使用方法或类属性。 Hangfire提供QueueAttribute
:
[Queue("myqueueformyserver")]
public void myMethod() { }
如果我了解您的要求,静态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);
}
}
}