Убедитесь, что выполнение задания Spring Quartz не перекрывается - PullRequest
44 голосов
/ 28 октября 2009

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

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

Ответы [ 7 ]

133 голосов
/ 28 октября 2009

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

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

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}
31 голосов
/ 28 октября 2009

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

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

18 голосов
/ 16 мая 2011

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

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

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

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

4 голосов
/ 27 августа 2014

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

    <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>
2 голосов
/ 28 октября 2009

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

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

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

0 голосов
/ 28 октября 2009

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

0 голосов
/ 28 октября 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...