quartz:防止作业中的作业并发实例.xml

2022-09-01 00:47:26

这应该很容易。我正在使用在Apache Tomcat 6.0.18下运行的Quartz,并且我有一个作业.xml文件,该文件设置了每分钟运行的计划作业。

我想做的是,如果下一个触发时间滚动时作业仍在运行,我不想启动新作业,因此我可以让旧实例完成。

有没有办法在作业中指定这一点.xml(防止并发实例)?

如果没有,有没有办法在应用程序的 Job 实现中共享对内存中单一实例的访问(这是通过 JobExecutionContext?),以便我可以自己处理并发?(并检测以前的实例是否正在运行)


更新:在文档中挣扎之后,我正在考虑以下几种方法,但要么不知道如何让它们工作,要么存在问题。

  1. 使用 StatefulJob。这将阻止并发访问...但我不确定如果我使用它会发生什么其他副作用,我也想避免以下情况:

    假设触发时间为每分钟,即触发器 #0 = 时间 0,触发器 #1 = 60000 毫秒,#2 = 120000,#3 = 180000 等,时间 0 的触发器 #0 触发我的作业,这需要 130000 毫秒。对于普通作业,这将在作业触发器 #0 仍在运行时执行触发器 #1 和 #2。使用 StatefulJob,这将按顺序执行触发器 #1 和 #2,紧随 #0 在 130000 处完成之后。我不想这样,我希望 #1 和 #2 不运行,下一个运行作业的触发器应该在 #3 (180000msec) 处发生。因此,我仍然必须对StatefulJob做其他事情才能让它以我想要的方式工作,所以我不认为使用它有什么好处。

  2. 使用 TriggerListener 从 vetoJobExecution() 返回 true。

    尽管实现该接口似乎很简单,但我必须弄清楚如何以声明方式设置 TriggerListener 的一个实例。找不到 xml 文件的文档

  3. 使用我的类拥有的实现 Job 的共享线程安全对象(例如信号量或其他对象)。static

    我不喜欢通过Tomcat / Quartz下的关键字使用单例的想法,不确定是否有副作用。另外,我真的不希望它们是真正的单例,只是与特定工作定义相关的东西。static

  4. 实现我自己的触发器,它扩展了 SimpleTrigger 并包含可以运行自己的 TriggerListener 的共享状态。

    同样,我不知道如何设置XML文件以使用此触发器而不是标准。<trigger><simple>...</simple></trigger>


答案 1

还有另一种更简单的解决方案。可以为作业提供 DisallowConcurrentExecution 的注释,以防止运行多个并发实例。请参阅此处的文档。

链接不断断开,因此这是相关示例。

@DisallowConcurrentExecution
public class ColorJob implements Job {

答案 2

dimitrisli的答案并不完整,所以这是我的答案。

当 Quartz Job 唤醒时,它会将其 JobExecutionContext 返回给您。我假设您希望跳过具有相同触发器的作业。

List<JobExecutionContext> jobs = jobExecutionContext.getScheduler().getCurrentlyExecutingJobs();
for (JobExecutionContext job : jobs) {
    if (job.getTrigger().equals(jobExecutionContext.getTrigger()) && !job.getJobInstance().equals(this)) {
        logger.info("There's another instance running, so leaving" + this);
        return;
    }
}

我们获取当前作业上下文,并检查是否存在具有相同触发器的上一个作业实例。如果是这种情况,我们只需跳过返回。


推荐