确保 Spring Quartz 作业执行不重叠

发布于 2024-08-09 00:13:27 字数 164 浏览 10 评论 0原文

我有一个 Java 程序,每 20 秒从 Spring Qquartz 执行一次。有时只需要几秒钟即可执行,但随着数据变大,我确信它会运行 20 秒或更长时间。

当一个实例仍在执行时,如何防止 Quartz 触发/触发作业?解雇两个在数据库上执行相同操作的作业不太好。有什么方法可以进行某种同步吗?

I have a Java program that executes from Spring Qquartz every 20 seconds. Sometimes it takes just few seconds to execute, but as data gets bigger I'm sure it run for 20 seconds or more.

How can I prevent Quartz from firing/triggering the job while one instance is still being executed? Firing 2 jobs performing same operations on a database would not be so good. Is there a way I can do some kind of synchronization?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

追我者格杀勿论 2024-08-16 00:13:27

Quartz 1

如果您更改类以实现 StatefulJob 而不是 Job,Quartz 将为您处理这个问题。来自 StatefulJob javadoc

有状态作业不允许
并发执行,这意味着新的
之前发生的触发器
完成execute(xx)方法
将会延迟。

StatefulJob 扩展了 Job 并且不添加任何新方法,因此要获得所需的行为,您所需要做的就是更改以下内容:

public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

改为:

public class YourJob implements org.quartz.StatefulJob {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Quartz 2

在 Quartz 2.0 版本中,不推荐使用 StatefulJob 。现在建议使用注释来代替,例如

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Quartz 1

If you change your class to implement StatefulJob instead of Job, Quartz will take care of this for you. From the StatefulJob javadoc:

stateful jobs are not allowed to
execute concurrently, which means new
triggers that occur before the
completion of the execute(xx) method
will be delayed.

StatefulJob extends Job and does not add any new methods, so all you need to do to get the behaviour you want is change this:

public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

To this:

public class YourJob implements org.quartz.StatefulJob {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Quartz 2

In version 2.0 of Quartz, StatefulJob is deprecated. It is now recommended to use annotations instead, e.g.

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}
两个我 2024-08-16 00:13:27

如果您需要做的只是每 20 秒触发一次,那么 Quartz 就显得严重矫枉过正了。 java.util.concurrent.ScheduledExecutorService 应该完全足以完成这项工作。

ScheduledExecutorService 还提供两种调度语义。 "固定速率" 将尝试每 20 秒运行一次作业,无论重叠情况如何,而 “固定延迟” 将尝试在第一个作业结束和下一个作业开始之间留出 20 秒。如果你想避免重叠,那么固定延迟是最安全的。

If all you need to do is fire every 20 seconds, Quartz is serious overkill. The java.util.concurrent.ScheduledExecutorService should be perfectly sufficient for that job.

The ScheduledExecutorService also provides two semantics for scheduling. "fixed rate" will attempt to run your job every 20 seconds regardless of overlap, whereas "fixed delay" will attempt to leave 20 seconds between the end of the first job and the start of the next. If you want to avoid overlap, then fixed-delay is safest.

允世 2024-08-16 00:13:27

以防万一有人提到这个问题,StatefulJob 已被弃用。他们现在建议您使用注释......

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

这将解释这些注释的含义......

注释导致的行为就像
他们的名字描述 - 多个
该工作的实例不会
允许同时运行(考虑
作业中包含代码的情况
execute() 方法需要 34 秒
运行,但它被安排为
每 30 次重复一次的触发器
秒),并将有其 JobDataMap
内容重新保留在
每次之后调度程序的 JobStore
执行。为此目的
举例,仅
@PersistJobDataAfterExecution
注释确实相关,但它是
总是明智地使用
@DisallowConcurrentExecution
用它注释,以防止
保存数据的竞争条件。

Just in case anyone references this question, StatefulJob has been deprecated. They now suggest you use annotations instead...

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

This will explain what those annotations mean...

The annotations cause behavior just as
their names describe - multiple
instances of the job will not be
allowed to run concurrently (consider
a case where a job has code in its
execute() method that takes 34 seconds
to run, but it is scheduled with a
trigger that repeats every 30
seconds), and will have its JobDataMap
contents re-persisted in the
scheduler's JobStore after each
execution. For the purposes of this
example, only
@PersistJobDataAfterExecution
annotation is truly relevant, but it's
always wise to use the
@DisallowConcurrentExecution
annotation with it, to prevent
race-conditions on saved data.

怎言笑 2024-08-16 00:13:27

如果你使用弹簧石英,我想你必须这样配置

    <bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myScheduler" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>

if you use spring quartz, i think you have to configure like this

    <bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myScheduler" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>
酒几许 2024-08-16 00:13:27

我不确定您是否想要同步,因为第二个任务将阻塞,直到第一个任务完成,并且您最终会积压。您可以将作业放入队列中,但从您的描述来看,队列可能会无限期地增长。

我会调查 ReadWriteLock s,并让您的任务在运行时设置锁定。未来的任务可以检查此锁,如果旧任务仍在运行,则立即退出。我从经验中发现这是解决这个问题最可靠的方法。

也许还会生成警告,以便您知道遇到问题并相应地增加时间间隔?

I'm not sure you want synchronisation, since the second task will block until the first finishes, and you'll end up with a backlog. You could put the jobs in a queue, but from your description it sounds like the queue may grow indefinitely.

I would investigate ReadWriteLocks, and let your task set a lock whilst it is running. Future tasks can inspect this lock, and exit immediately if an old task is still running. I've found from experience that that's the most reliable way to approach this.

Perhaps generate a warning as well so you know you're encountering problems and increase the time interval accordingly ?

鸠魁 2024-08-16 00:13:27

您可以使用信号量。当信号量被拿走时,放弃第二项工作,等待下一次触发时间。

You can use a semaphore. When the semaphore is taken, abandon the 2nd job and wait until the next fire time.

你的笑 2024-08-16 00:13:27

将它们放入队列

即使时间超过 20 秒,当前作业也应该完成 &那么应该从队列中获取下一个。

或者您也可以将时间增加到合理的范围。

put them in a queue

Even if the time exceeds 20 second current job should be finished & then the next should be fetched from the queue.

Or you can also increase time to some reasonable amount.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文