Убедитесь, что выполнение заданий Spring Quartz не перекрывается

У меня есть программа Java, которая запускается из Spring Qquartz каждые 20 секунд. Иногда для выполнения требуется всего несколько секунд, но по мере увеличения объема данных я уверен, что он выполняется в течение 20 секунд или больше.

Как я могу запретить Quartz запускать / запускать задание, пока один экземпляр все еще выполняется? Запуск двух заданий, выполняющих одни и те же операции с базой данных, был бы не очень хорошим. Есть ли способ сделать какую-то синхронизацию?


person ant    schedule 28.10.2009    source источник


Ответы (7)


Если все, что вам нужно делать, это стрелять каждые 20 секунд, Quartz - серьезный перебор. java.util.concurrent.ScheduledExecutorService должно быть вполне достаточно для этой работы.

ScheduledExecutorService также предоставляет две семантики для планирования. " fixed rate " будет пытаться запускать ваше задание каждые 20 секунд независимо от перекрытия, тогда как «fixed delay» попытается оставить 20 секунд между концом первого задания и началом следующего. Если вы хотите избежать перекрытия, то лучше всего использовать фиксированную задержку.

person skaffman    schedule 28.10.2009
comment
Или, конечно, Spring TaskScheduler, если вы хотите остаться в Spring. - person Michael Piefel; 09.06.2012
comment
Верно, если не в кластере - person David Mann; 16.10.2013
comment
Похоже, что более поздние версии ScheduledExecutorService никогда не будут одновременно выполняться в соответствии с документация. Если выполнение этой задачи занимает больше времени, чем ее период, последующие выполнения могут начаться с опозданием, но не будут выполняться одновременно. - person Sovietaced; 06.08.2020

Кварц 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*/}
}

Кварц 2

В Quartz версии 2.0 StatefulJob устарел. Вместо этого рекомендуется использовать аннотации, например

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}
person Dónal    schedule 28.10.2009
comment
С этим решением попытки экземпляров задания выстраиваются в очередь, верно? Как сделать так, чтобы они не выстраивались в очередь? - person Jay Sullivan; 17.10.2013
comment
Правильный ответ таков. Почему OP принял другой ответ, который просто предлагает альтернативный способ? - person Saeed Neamati; 09.12.2013
comment
@Donal Как аннотация DisallowConcurrentExecution поддерживает отсутствие параллелизма между несколькими экземплярами сервера или нет? - person greperror; 17.01.2018
comment
@greperror Если вы хотите предотвратить выполнение параллелизма на нескольких экземплярах сервера, ознакомьтесь с @PersistJobDataAfterExecution - person Dónal; 18.01.2018

На всякий случай, если кто-то ссылается на этот вопрос, StatefulJob устарел. Теперь они предлагают вам использовать аннотации ...

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

Это объяснит, что означают эти аннотации ...

Аннотации вызывают поведение точно так же, как описывают их имена - нескольким экземплярам задания не будет разрешено запускаться одновременно (рассмотрим случай, когда в методе execute () задания есть код, выполнение которого занимает 34 секунды, но оно запланировано с помощью триггер, который повторяется каждые 30 секунд), и его содержимое JobDataMap будет повторно сохраняться в JobStore планировщика после каждого выполнения. Для целей этого примера действительно актуальна только аннотация @PersistJobDataAfterExecution, но всегда разумно использовать с ней аннотацию @DisallowConcurrentExecution, чтобы предотвратить условия гонки для сохраненных данных.

person gshauger    schedule 16.05.2011

если вы используете пружинный кварц, я думаю, вам нужно настроить так

    <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>
person Paul    schedule 27.08.2014
comment
работает как шарм, может быть в таком коде MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean(); jobDetail.setConcurrent(false); jobDetail.setBeanName("Job_" + jobId); jobDetail.setTargetObject(job); jobDetail.setTargetMethod("execute"); jobDetail.setConcurrent(false); - person Amare; 03.10.2017
comment
Милая. Спасибо. - person Joel; 20.09.2018

Я не уверен, что вам нужна синхронизация, так как вторая задача будет заблокирована до завершения первой, и вы получите отставание. Вы можете поставить задания в очередь, но из вашего описания похоже, что очередь может расти бесконечно.

Я бы исследовал ReadWriteLock s, и пусть ваша задача установит блокировку во время выполнения. Будущие задачи могут проверить эту блокировку и немедленно выйти, если старая задача все еще выполняется. По опыту я убедился, что это самый надежный способ подойти к этому.

Возможно, вы также создадите предупреждение, чтобы знать, что столкнулись с проблемами, и соответственно увеличить временной интервал?

person Brian Agnew    schedule 28.10.2009

поставить их в очередь

Даже если время превышает 20 секунд, текущее задание должно быть завершено, а следующее должно быть выбрано из очереди.

Или вы также можете увеличить время до некоторой разумной суммы.

person Asad Khan    schedule 28.10.2009

Вы можете использовать семафор. Когда семафор занят, откажитесь от 2-го задания и дождитесь следующего срабатывания.

person Salandur    schedule 28.10.2009