如何防止Hangfire重复作业在连续执行30分钟后重新启动

问题描述 投票:5回答:3

我正在使用asp.net mvc-5 Web应用程序,我在使用Hangfire工具运行长时间运行的后台作业时遇到了问题。问题是如果作业执行超过30分钟,那么hangfire会自动启动另一个作业,所以我最终会同时运行两个类似的作业。

现在我有以下内容: -

  1. Asp.net mvc-5
  2. US-8
  3. Hangfire 1.4.6
  4. Windows服务器2012

现在我已经定义了一个每天17:00运行的篝火重复工作。后台作业主要扫描我们的网络中的服务器和虚拟机并更新数据库,定期作业将在完成执行后发送电子邮件。经常性工作在执行时间不到30分钟时效果很好。但是今天随着我们的系统的发展,经常性的工作在40分钟后完成,而不是像过去那样在22-25分钟之后完成。我收到了2封电子邮件,而不是一封电子邮件(电子邮件之间的时间约为30分钟)。现在我手动重新运行这个工作,我注意到问题如下: -

“当定期作业达到30分钟连续执行时,定期作业的新实例将启动,因此我将有两个实例而不是同时运行的实例,这就是我收到2封电子邮件的原因。”

现在,如果定期工作不到30分钟(例如29分钟),我将不会遇到任何问题,但如果重复执行的工作超过30分钟,那么由于某种原因或其他原因,将启动一项新工作。虽然当我在执行作业期间访问hangfire仪表板时,我发现只有一个活动作业,当我监视我的数据库时,我可以从sql profiler看到有两个作业访问数据库。这种情况发生在经常性工作开始30分钟后(在我们的案例中是17:30),这就是为什么我收到2封电子邮件,这意味着2个重复工作在后台运行而不是一个。

那么有人可以提出这方面的建议,如果目前的重复工作执行时间超过30分钟,我怎么能避免因自动启动新的重复工作而引发的篝火?谢谢

asp.net iis asp.net-mvc-5 background-process hangfire
3个回答
15
投票

你看过InvisibilityTimeoutHangfire docs设置吗?

默认SQL Server作业存储实现使用常规表作为作业队列。为了确保在意外的进程终止时不会丢失作业,只有在成功完成后才会从队列中删除它。

为了使其与其他工作者不可见,带有OUTPUT子句的UPDATE语句用于获取排队的作业并以原子方式更新FetchedAt值(为其他工作者发出信号)。其他工作人员看到获取的时间戳并忽略了工作。但是为了处理进程终止,他们将仅在指定的时间内(默认为30分钟)忽略作业。

尽管此机制可确保处理每个作业,但有时可能会导致重试延迟时间过长或导致多个作业执行。请考虑以下情形:

  1. 工人A找到一份工作(运行一小时)并在12:00开始工作。
  2. 工作人员B在12:30获取相同的工作,因为默认的不可见性超时已过期。
  3. 13:00工作者C(没有获取)相同的工作,因为(成功执行后它将被删除。)

如果您使用取消令牌,则将在12:30为工人A设置,为工人B设置为13:00。这可能导致您的长期工作永远不会被执行。如果您没有使用取消令牌,它将由WorkerA和Worker B同时执行(从12:30开始),但是Worker C将不会获取它,因为它将在成功执行后删除。

因此,如果您有长时间运行的作业,最好配置不可见性超时间隔:

var options = new SqlServerStorageOptions
{
    InvisibilityTimeout = TimeSpan.FromMinutes(30) // default value
};

GlobalConfiguration.Configuration.UseSqlServerStorage("<name or connection string>", options);

截至Hangfire 1.5 this option is now Obsolete。正在进行的工作对其他工人来说是不可见的。

在使用SQL Server 30分钟(默认情况下)后,告别将隐身超时与意外的后台作业重试混淆。新的Hangfire.SqlServer实现使用普通旧事务来获取后台作业并将其隐藏在其他工作者之外。

即使在非正常关机后,该工作也会立即为其他工作人员提供,不会有任何延误。


6
投票

我无法找到关于如何正确地为Postgresql数据库执行此操作的文档,我看到的每个示例都使用sqlserver,我发现隐身超时是PostgreSqlStorageOptions对象中的属性,我在此处找到:https://github.com/frankhommers/Hangfire.PostgreSql/blob/master/src/Hangfire.PostgreSql/PostgreSqlStorageOptions.cs#L36。幸运的是,通过反复试验,我能够发现UsePostgreSqlStorage有一个重载来接受这个对象。对于.Net Core 2.0,当您在启动类的ConfigureServices方法中设置hangfire postgresql DB时添加此项(默认超时设置为30分钟):

    services.AddHangfire(config =>
            config.UsePostgreSqlStorage(Configuration.GetConnectionString("Hangfire1ConnectionString"), new PostgreSqlStorageOptions {
                InvisibilityTimeout = TimeSpan.FromMinutes(720)

            }));

1
投票

使用Hangfire.MemoryStorage作为存储提供程序时遇到此问题。对于内存存储,您需要在FetchNextJobTimeout中设置MemoryStorageOptions,否则默认情况下,作业将在30分钟后超时并执行新作业。

var options = new MemoryStorageOptions
{
    FetchNextJobTimeout = TimeSpan.FromDays(1)
};
GlobalConfiguration.Configuration.UseMemoryStorage(options);
© www.soinside.com 2019 - 2024. All rights reserved.