首页 > 解决方案 > Quart.Net 有时会运行重叠的任务

问题描述

Quartz.Net 3.0.7用来管理调度程序。在我的测试环境中,我有两个正在运行的调度程序实例。我有一个测试过程在结束前运行了整整 2 小时。Quartz 配置为每 10 秒启动一次进程,我正在使用该DisallowConcurrentExecution属性来防止任务的多个实例同时运行。80% 的时间这是按预期工作的。Quartz 将启动进程并阻止任务的任何其他实例启动,直到初始实例完成。如果我停止托管 Quart 的两个服务中的一个,那么另一个实例会在下一个 10 秒标记处执行任务。

然而,在让这两个 Quartz 服务不间断地运行 48 小时后,我发现有几次事情发生了可怕的错误。有时主机 B 会启动任务,即使任务仍在主机 A 上执行 2 小时的中间。有一次我什至发现该进程在主机 B 上启动了 3 次,都在 10 分钟内时期。因此,在两个小时内,一项任务同时运行了三个实例。在所有三个完成后,Quartz 回到预期的计划,一次只运行一个实例。

如果这些重叠的任务在 100% 的时间内发生,我会认为我的结果有问题,但由于它似乎只有大约 20% 的时间发生,我认为这一定是 Quartz 实现中的某些东西。这是设计使然还是错误?如果有一个我可以捕获的事件Quart.Net告诉我某个任务的另一个实例已经启动,我可以监听它并停止现有任务的运行。我只需要确保DisallowConcurrentExecution遵守并防止任务同时运行多个实例。谢谢。

编辑:我添加了使用 context.Scheduler.GetCurrentlyExecutingJobs 的逻辑,以在我的任务启动时查找具有相同 JobDetail.Key 但不同 FireInstanceId 的任何作业。如果我发现另一个当前正在执行的作业,我将阻止这个实例做任何事情。我发现在重复并发场景中,Quartz 报告当前没有使用相同 JobDetail.Key 执行的其他作业。这应该是可能的吗?在什么情况下 Quartz.Net 会启动一个 IJob,几分钟后会忘记它是一个正在执行的作业,但允许它继续执行而不取消 CancellationToken?

Edit2:我在我的日志中找到了一个实例,Quartz 按预期启动了一个任务。然后,一分钟后,Quartz 尝试启动另外 9 个实例,每个实例都有不同的 FireInstanceId。GetCurrentlyExecutingJobs我的自定义代码阻止了另外 9 个实例,因为它可以通过调用获取正在运行的作业列表来看到原始实例仍在运行。我仔细检查了ConcurrentExecutionDisallowed一下,运行时所有任务的标志都为真,所以我希望 Quartz 可以防止重复实例。这听起来像一个错误。我是否应该手动处理这个问题,或者我应该希望 Quartz 能做到这一点?

Edit3:我肯定在看两个不同的问题。在这两种情况下,Quartz.Net 都会使用新的 FireInstanceId 启动我的 IJob 实例,而已经有另一个 FireInstanceId 正在为同一个 JobKey 运行。在一种情况下,我可以通过调用 GetCurrentlyExecutingJobs 看到两个 FireInstanceId 都处于活动状态。在第二种情况下,调用 GetCurrentlyExecutingJobs 显示第一个 FireInstanceId 不再运行,即使我可以从日志中看到原始实例仍在运行。这两种情况都会导致我的 IJob 的多个实例同时运行,这是不可接受的。通过在 IJob 启动时调用 GetCurrentlyExecutingJobs 来解决第一种情况很容易,但第二种情况更难。如果它的 FireInstanceId 已从活动列表中消失,我将不得不每隔一段时间 ping GetCurrentlyExecutingJobs 并停止该任务。其他人真的没有注意到这种行为吗?

标签: quartz.net

解决方案


I found that if I set this option, that I no longer have overlapping executing jobs. I still wish that Quartz would cancel the job’s cancellation token, though, if it lost track of the executing job.

QuartzProperties.Add("quartz.jobStore.clusterCheckinInterval", "60000");

推荐阅读