在将Hangfire(v1.7.7)设置为always run之后,所有重复出现的作业将在重新启动IIS或回收池后立即执行。这是不受欢迎的行为,因为我们计划将作业每月一次或每周运行一次,并且每次部署都会使它们运行。
我们无法在文档或论坛中找到配置属性来防止此行为,我们仍在分析存储库,试图寻找线索。
我们发现this issue和this discussion与我们的问题有关。
除了上面提供的链接之外,它代表我们为使Hangfire始终运行而进行的确切配置,这是我们当前的配置:
private BackgroundJobServer _backgroundJobServer;
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireRestrictiveAuthorizationFilter() },
StatsPollingInterval = UM_MINUTO_EM_MILISEGUNDOS * 10
});
GlobalConfiguration.Configuration.UseSqlServerStorage("Implanta", new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SchemaName = "HangFireSiscaf",
SlidingInvisibilityTimeout = null
});
_backgroundJobServer = new BackgroundJobServer(new BackgroundJobServerOptions()
{
Queues = new[] { "siscaf" },
ServerName = "SISCAF.NET",
WorkerCount = 5
});
这就是我们通常安排定期作业的方式(几个方法名称和字符串写在pt-BR中):
RecurringJob.AddOrUpdate<ColetaMensalCFATask>(
ColetaMensalCFATask.Key,
x => x.ExecuteTask(),
Cron.Monthly(diaAgendamentoMensalColetaCFA, timeSpanHoraAgendamentoMensalColetaCFA.Minutes),
TimeZoneInfo.Local,
"siscaf");
更新1: 通过删除作业执行历史记录并将每个作业添加为新作业,我们能够重现所需的行为。但是,这不是令人满意的解决方案。
答案 0 :(得分:1)
每当需要在Hangfire中更改行为时,都必须编写JobFilter。
此类可以实现各种接口,但是在您的情况下,您可以实现IClientFilter
并检入OnCreating()
,是否应该创建作业或实现IElectStateFilter
并检入{{ 1}},是否应将工作入队。
请注意,已经存在许多其他作业筛选器,并且它们以定义的顺序执行,由OnStateElection()
属性中的整数值给出。为了确保您的过滤器将是最后一个过滤器,请将其设置为Order
。
要将此作业过滤器应用于您的作业,可以将属性添加到方法或类中,或者如果应该为每个作业执行该属性,则可以在启动时通过int.MaxValue
将实例添加到全局列表中
如果您在过滤器方法之一中,则每个方法都有一个GlobalJobFilters.Filters.Add()
属性,该属性可以通过context
属性访问监视api:
Storage
当前,在重新创建定期作业的情况下,我无法检查它们包含的内容,但是如果您使用调试器进行查看,则应该找到有关定期作业的信息。一种简单的检查方法是查看Hangfire仪表板。如果您打开任务详细信息页面并找到任何链接到该周期性任务的内容,而该内容无法通过监视API获得,则导致所有Hangfire网页都使用此API获取其内容。
只需更深入地挖掘,发现要点即可根据给定的作业ID从重复作业中检索所有信息:
var monitor = context.Storage.GetMonitoringApi();
var jobDetails = monitor.JobDetails(context.BackgroundJob.Id);
foreach (var kvp in jobDetails.Properties)
{
Trace.WriteLine($"{kvp.Key => kvp.Value}");
}
foreach (var entry in jobDetails.History.OrderBy(e => e.CreatedAt))
{
Trace.WriteLine($"{entry.StateName} ({entry.CreatedAt}): {Reason}");
foreach (var kvp in entry.Data)
{
Trace.WriteLine($" {kvp.Key} => {kvp.Value}");
}
}
周期性作业的入队状态始终是文本var monitor = context.Storage.GetMonitoringApi();
var jobDetails = monitor.JobDetails(context.BackgroundJob.Id);
if(jobDetails.Properties.TryGetValue("RecurringJobId", out string recurringId))
{
var values = context.Connection.GetAllEntriesFromHash($"recurring-job:{recurringId}");
foreach (var kvp in values)
{
Trace.WriteLine($"{kvp.Key} => {kvp.Value}");
}
}
的原因,该文本可以用作这样的过滤器:
Triggered by recurring job scheduler