且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-16 14:29:02

您是否查看了 Hangfire 文档?

Did you look at InvisibilityTimeout setting from the Hangfire docs?

默认的 SQL Server 作业存储实现使用常规表作为作业队列.确保在以下情况下不会丢失工作意外的进程终止,仅从队列中删除成功完成后.

Default SQL Server job storage implementation uses a regular table as a job queue. To be sure that a job will not be lost in case of unexpected process termination, it is deleted only from a queue only upon a successful completion.

为了使其对其他工作人员不可见,UPDATE 语句带有OUTPUT 子句用于获取排队的作业并更新 FetchedAt值(向其他工作人员发出信号,表明它已被提取)在一个原子方式.其他工作人员看到获取的时间戳并忽略作业.但是为了处理进程终止,他们只会忽略一个工作在指定的时间内(默认为 30 分钟).

To make it invisible from other workers, the UPDATE statement with OUTPUT clause is used to fetch a queued job and update the FetchedAt value (that signals for other workers that it was fetched) in an atomic way. Other workers see the fetched timestamp and ignore a job. But to handle the process termination, they will ignore a job only during a specified amount of time (defaults to 30 minutes).

虽然这个机制保证了每一个作业都会被处理,有时它可能会导致重试延迟过长或导致多个作业执行.考虑以下场景:

Although this mechanism ensures that every job will be processed, sometimes it may cause either long retry latency or lead to multiple job execution. Consider the following scenario:

  1. 工人 A 获取了一个作业(运行了一个小时)并在 12:00 开始它.
  2. 工人 B 在 12:30 获取了相同的作业,因为默认的隐身超时已过期.
  3. 工人 C(未提取)在 13:00 执行相同的作业,因为(它表演成功后将被删除.)

如果您使用取消令牌,它将为工人 A 设置在12:30 和工人 B 的 13:00.这可能会导致您的永远不会执行长时间运行的作业.如果您不使用取消令牌,它将由 WorkerA 和工人 B(从 12:30 开始),但工人 C 不会去取它,因为它表演成功后将被删除.

If you are using cancellation tokens, it will be set for Worker A at 12:30, and at 13:00 for Worker B. This may lead to the fact that your long-running job will never be executed. If you aren’t using cancellation tokens, it will be concurrently executed by WorkerA and Worker B (since 12:30), but Worker C will not fetch it, because it will be deleted after successful performance.

因此,如果您有长时间运行的作业,***配置隐身超时间隔:

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

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

截至 Hangfire 1.5 这个选项现在 Obsolete.其他工人看不到正在从事的工作.

As of Hangfire 1.5 this option is now Obsolete. Jobs that are being worked on are invisible to other workers.

告别将隐身超时与意外混淆使用 SQL 时后台作业在 30 分钟后重试(默认情况下)服务器.新的 Hangfire.SqlServer 实现使用普通的旧获取后台作业并将它们隐藏起来的事务工人.

Say goodbye to confusing invisibility timeout with unexpected background job retries after 30 minutes (by default) when using SQL Server. New Hangfire.SqlServer implementation uses plain old transactions to fetch background jobs and hide them from other workers.

即使在非正常关机后,该作业仍可用于其他工人立即,没有任何延误.

Even after ungraceful shutdown, the job will be available for other workers instantly, without any delays.