我正在开发一个asp.net mvc-5 Web应用程序,我在使用Hangfire工具运行长时间运行的后台作业时遇到了问题。 问题是,如果作业执行时间超过30分钟,那么hangfire将自动启动另一个作业,因此我最终会同时运行两个类似的作业。
现在我有以下内容: -
现在我已经定义了一个每天17:00运行的篝火重复工作。后台作业主要扫描我们的网络中的服务器和虚拟机并更新数据库,定期作业将在完成执行后发送电子邮件。 经常性工作在执行时间不到30分钟时效果很好。但是今天随着我们的系统的发展,经常性的工作在40分钟后完成,而不是像过去那样在22-25分钟之后完成。我收到了2封电子邮件,而不是一封电子邮件(电子邮件之间的时间约为30分钟)。现在我手动重新运行这个工作,我注意到问题如下: -
“当经常性工作连续执行30分钟时,a 定期工作的新实例将开始,所以我将有两个 实例而不是同时运行的实例,这就是我收到2封电子邮件的原因。“
现在,如果定期工作不到30分钟(例如29分钟),我将不会遇到任何问题,但如果定期执行的工作超过30分钟,那么由于某种原因或其他原因,将启动一项新工作。 虽然当我在执行作业期间访问hangfire仪表板时,我发现只有一个活动作业,当我监视我的数据库时,我可以从sql profiler看到有两个作业访问数据库。这种情况发生在经常性工作开始30分钟后(在我们的案例中为17:30),这就是为什么我收到2封电子邮件,这意味着2个重复工作在后台运行而不是一个。
所以有人可以提出这方面的建议吗,如果目前的重复工作执行时间超过30分钟,我怎么能避免因自动启动新的定期工作而引发的篝火? 谢谢
答案 0 :(得分:14)
您是否从Hangfire docs了解了InvisibilityTimeout
设置?
默认SQL Server作业存储实现使用常规表作为 一份工作队列。为了确保工作不会丢失,以防万一 意外的进程终止,它仅从队列中删除 成功完成后。
要使其与其他worker不可见,请使用UPDATE语句 OUTPUT子句用于获取排队作业并更新FetchedAt 价值(表明其获取的其他工人的信号) 原子方式。其他工作人员看到获取的时间戳并忽略了工作。 但是为了处理流程终止,他们只会忽略一份工作 在指定的时间内(默认为30分钟)。
虽然这种机制可以确保每个作业都得到处理, 有时它可能会导致长时间的重试延迟或导致多次 工作执行。请考虑以下情形:
- 工人A取了一份工作(运行了一个小时)并在12:00开始工作。
- 工作人员B在12:30获取相同的工作,因为默认的不可见超时已过期。
- 工人C(没有取得)同样的工作在13:00,因为(它 成功演出后将被删除。)
醇>如果您使用取消令牌,则将为工人A设置 工人B的12:30和13:00。这可能导致你的事实 长期工作永远不会被执行。如果你不使用 取消令牌,它将由WorkerA和 工人B(从12:30开始),但是工人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时,在30分钟后(默认情况下)后台作业重试 服务器。新的Hangfire.SqlServer实现使用普通的旧版本 用于获取后台作业并将其隐藏在其他作业中的事务 工人。
即使在非正常关机后,该工作也可供其他人使用 工人们立即,没有任何延误。
答案 1 :(得分:5)
我在查找有关如何正确配置Postgresql数据库的文档时遇到了麻烦,我看到的每个示例都在使用sqlserver,我发现隐形超时是PostgreSqlStorageOptions对象内部的一个属性,我在这里找到了:{{ 3}}。幸运的是,通过反复试验,我能够确定UsePostgreSqlStorage有一个重载来接受该对象。对于.Net Core 2.0,当您在启动类的ConfigureServices方法中设置hangfire postgresql DB时,添加以下内容(默认超时设置为30分钟):
mm.astype(int)
答案 2 :(得分:0)
在使用Hangfire.MemoryStorage作为存储提供程序时遇到了这个问题。使用内存存储时,您需要在FetchNextJobTimeout
中设置MemoryStorageOptions
,否则默认情况下作业将在30分钟后超时并执行新的作业。
var options = new MemoryStorageOptions
{
FetchNextJobTimeout = TimeSpan.FromDays(1)
};
GlobalConfiguration.Configuration.UseMemoryStorage(options);
答案 3 :(得分:0)
仅想指出一点,即使在下面的thing中指出:
截至Hangfire 1.5 this option is now Obsolete。其他工人看不到正在处理的工作。
告别使用SQL Server时30分钟(默认情况下)后30分钟(默认情况下)后,隐身超时与意外的后台作业重试混淆了。新的
Hangfire.SqlServer
实现使用普通的旧事务来获取后台作业并将其对其他工作人员隐藏。即使不愉快地关闭后,该工作也将立即可供其他工人使用,而不会出现任何延迟。
对于许多使用MySQL,PostgreSQL,MongoDB的人来说,InvisibilityTimeout
仍然是走的路:https://github.com/HangfireIO/Hangfire/issues/1197