如何在IIS重新启动后防止hangfire重复执行作业?

问题描述 投票:0回答:1

[将Hangfire(v1.7.7)设置为always run后,所有重复出现的作业将在重新启动IIS或回收池后立即执行。这是不受欢迎的行为,因为我们计划将作业每月一次或每周运行一次,并且每次部署都会使它们运行。

我们无法在文档或论坛中找到配置属性来防止此行为,我们仍在分析存储库,以寻求线索。

我们发现this issuethis 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");

UPDATE 1:通过删除作业执行历史记录并将每个作业添加为新作业,我们能够重现所需的行为。但不是令人满意的解决方案。

c# .net hangfire
1个回答
0
投票

[每当您需要在Hangfire中更改行为时,都必须写JobFilter

此类可以实现各种接口,但是在您的情况下,您可以实现IClientFilter并检入OnCreating()是否应创建作业,或者实现IElectStateFilter并检入OnStateElection()是否应将作业入队。

[请注意,已经有许多其他作业筛选器,并且它们以定义的顺序执行,由Order属性中的整数值给出。为了确保您的过滤器将是最后一个过滤器,请将其设置为int.MaxValue

要将此作业过滤器应用于您的作业,您可以将属性添加到方法或类,或者如果应该为每个作业执行该属性,则可以在启动时通过GlobalJobFilters.Filters.Add()将实例添加到全局列表。

如果您在其中一个过滤器方法中,则每个方法都具有context属性,该属性可以通过Storage属性访问监视api:

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

当前,如果是新创建的重复作业,我无法检查它们包含的内容,但是如果您使用调试器进行查看,则应该找到有关重复作业的一些信息。一种简单的检查方法是查看Hangfire仪表板。如果您打开工作详细信息页面,并且找到任何链接到该重复性工作的内容,而该内容无法通过监视API获得,则导致所有Hangfire网页都使用此API来获取其内容。

只是稍微深入一点,发现要点就可以通过给定的作业ID从重复作业中检索所有信息:

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的原因,该文本可以像这样用作过滤器:

    public void OnStateElection(ElectStateContext context)
    {
        switch (context.CandidateState)
        {
            case EnqueuedState enqueued when enqueued.Reason == "Triggered by recurring job scheduler":
                Trace.WriteLine($"Was triggered by job scheduler.");

                // Skip all jobs of job scheduler
                context.CandidateState = new SucceededState(null, 0, 0);
                break;
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.