作业 1 计划每 5 分钟运行一次,大约需要 1 分钟才能完成。
大量工作堆积起来,作业 1 需要 15 分钟才能运行。
现在有三个 Job 1's 正在同时处理 - 我不想要这样。
是否有 Hangfire 设置,或者我需要手动轮询作业状态?
您可以使用 DisableConcurrentExecution 属性来防止同时执行多个方法。只需将此属性放在您的方法之上 -
[DisableConcurrentExecution(timeoutInSeconds: 10 * 60)]
public void Job1()
{
// Metohd body
}
有点晚了,但我正在使用此类来防止重复的作业同时运行
public class SkipConcurrentExecutionAttribute : JobFilterAttribute, IServerFilter, IElectStateFilter
{
private readonly int _timeoutSeconds;
private const string DistributedLock = "DistributedLock";
public SkipConcurrentExecutionAttribute(int timeOutSeconds)
{
if (timeOutSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");
this._timeoutSeconds = timeOutSeconds;
}
public void OnPerformed(PerformedContext filterContext)
{
if (!filterContext.Items.ContainsKey(DistributedLock))
throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
var distributedLock = (IDisposable)filterContext.Items[DistributedLock];
distributedLock?.Dispose();
}
public void OnPerforming(PerformingContext filterContext)
{
filterContext.WriteLine("Job Started");
var resource = String.Format(
"{0}.{1}",
filterContext.BackgroundJob.Job.Type.FullName,
filterContext.BackgroundJob.Job.Method.Name);
var timeOut = TimeSpan.FromSeconds(_timeoutSeconds);
filterContext.WriteLine($"Waiting for running jobs to complete. (timeout: { _timeoutSeconds })");
try
{
var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeOut);
filterContext.Items[DistributedLock] = distributedLock;
}
catch (Exception ex)
{
filterContext.WriteLine(ex);
filterContext.WriteLine("Another job is already running, aborted.");
filterContext.Canceled = true;
}
}
public void OnStateElection(ElectStateContext context)
{
//if (context.CandidateState as FailedState != null)
//{
//}
}
}
希望有帮助,谢谢!
有一个名为“DisableConcurrentExecution”的属性,可以防止 2 个相同类型的作业同时运行。
不过,就您的情况而言,最好检查任务是否运行并相应地跳过。
听起来您可能会对以下内容感兴趣: https://discuss.hangfire.io/t/job-reentrancy-avoidance-proposal/607/8
讨论的是跳过将与已运行的作业同时执行的作业。
我解决了这个问题。我希望它对你有用
public class PreventConcurrentExecutionJobFilter : JobFilterAttribute, IClientFilter, IServerFilter
{
public void OnCreating(CreatingContext filterContext)
{
var jobs = JobStorage.Current.GetMonitoringApi().ProcessingJobs(0, 100);
if (jobs.Count(x => x.Value.Job.Type == filterContext.Job.Type && string.Join(".", x.Value.Job.Arguments) == string.Join(".", filterContext.Job.Arguments)) > 0)
{
filterContext.Canceled = true;
}
}
public void OnPerformed(PerformedContext filterContext) { }
void IClientFilter.OnCreated(CreatedContext filterContext) { }
void IServerFilter.OnPerforming(PerformingContext filterContext) { }
}
用途:
GlobalJobFilters.Filters.Add(new PreventConcurrentExecutionJobFilter());
[PreventConcurrentExecutionJobFilter]
public abstract class IHangfireJob {
}
[PreventConcurrentExecutionJobFilter]
public class MyJob {
}
我在 RecurringJob 中使用了 DisableConcurrentExecution 属性,但它对我不起作用。
我的错误是我在我的方法上使用它,而不是在我的界面上。
[DisableConcurrentExecution(timeoutInSeconds: 10 * 60)]
Task SyncAllMyDataAsync();
RecurringJob.AddOrUpdate<IMySyncJobs>("Sync my data", x => x.SyncAllMyDataAsync(), "0 0 * * * *");
是的。可以如下:
RecurringJob.AddOrUpdate(Environment.MachineName, () => MyJob(Environment.MachineName), Cron.HourInterval(2));
MyJob 应该这样定义:
public void MyJob(string taskId)
{
if (!taskId.Equals(Environment.MachineName))
{
return;
}
//Do whatever you job should do.
}
就我而言,我有许多并行运行的方法,但我不能多次运行相同的方法。
使用本主题中的解决方案,我刚刚编辑了查询。如果处理列表中已有一个与实际方法同名的方法,则取消执行。
我相信这可以解决很多案例。
using Hangfire.Client;
using Hangfire.Common;
using Hangfire.Server;
using Hangfire;
public class PreventConcurrentExecutionJobFilter : JobFilterAttribute, IClientFilter, IServerFilter
{
public void OnCreating(CreatingContext filterContext)
{
var jobs = JobStorage.Current.GetMonitoringApi().ProcessingJobs(0, 100);
var methodAlreadyProcessing = jobs.Any(x => x.Value.Job.Method.Name == filterContext.Job.Method.Name);
if (methodAlreadyProcessing)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Job {filterContext.Job.Method.Name} cancelled why was already exists in processing list!");
filterContext.Canceled = true;
}
}
public void OnPerformed(PerformedContext filterContext) { }
void IClientFilter.OnCreated(CreatedContext filterContext) { }
void IServerFilter.OnPerforming(PerformingContext filterContext) { }
}
[PreventConcurrentExecutionJobFilter]
public async Task MyTopTask()
{
...
}
如果你想放弃尝试运行某件事两次(如果它已经在运行),你总是可以这样做(注意没有应用属性):
private static bool _isRunningUpdateOrders;
public void UpdateOrders()
{
try
{
if (_isRunningUpdateOrders)
{
return;
}
_isRunningUpdateOrders = true;
// Logic...
}
finally
{
_ isRunningUpdateOrders = false;
}
}
编辑:请仅使用类似的方法作为快速解决方案,例如如果您刚刚发现有问题并且仍在评估更好的解决方案:-)或者如果您很懒并且只想“有点”解决问题;-)