Перейти к основному содержимому

Как запустить и остановить запланированное пакетное задание Spring

· 3 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В этом руководстве мы рассмотрим и сравним различные способы запуска и остановки запланированного задания Spring Batch для любых необходимых бизнес-кейсов.

Если вам нужны общие сведения о Spring Batch и Scheduler, обратитесь к статьям Spring-Batch и Spring-Scheduler .

2. Запустите запланированное пакетное задание Spring

Во-первых, у нас есть класс SpringBatchScheduler для настройки планирования и пакетного задания. Метод launchJob() будет зарегистрирован как запланированная задача.

Кроме того, чтобы запустить запланированное задание Spring Batch наиболее интуитивно понятным способом, давайте добавим условный флаг, чтобы запускать задание только тогда, когда для флага установлено значение true:

private AtomicBoolean enabled = new AtomicBoolean(true);

private AtomicInteger batchRunCounter = new AtomicInteger(0);

@Scheduled(fixedRate = 2000)
public void launchJob() throws Exception {
if (enabled.get()) {
Date date = new Date();
JobExecution jobExecution = jobLauncher()
.run(job(), new JobParametersBuilder()
.addDate("launchDate", date)
.toJobParameters());
batchRunCounter.incrementAndGet();
}
}

// stop, start functions (changing the flag of enabled)

Переменная batchRunCounter будет использоваться в интеграционных тестах для проверки того, было ли остановлено пакетное задание.

3. Остановить запланированное пакетное задание Spring

С указанным выше условным флагом мы можем запустить запланированное задание Spring Batch с активной запланированной задачей.

Если нам не нужно возобновлять задание, мы можем фактически остановить запланированное задание для экономии ресурсов.

Давайте рассмотрим два варианта в следующих двух подразделах.

3.1. Использование планировщика постпроцессора

Поскольку мы планируем метод с помощью аннотации @Scheduled , постпроцессор компонента ScheduledAnnotationBeanPostProcessor должен быть зарегистрирован первым.

Мы можем явно вызвать postProcessBeforeDestruction() для уничтожения данного запланированного компонента:

@Test
public void stopJobSchedulerWhenSchedulerDestroyed() throws Exception {
ScheduledAnnotationBeanPostProcessor bean = context
.getBean(ScheduledAnnotationBeanPostProcessor.class);
SpringBatchScheduler schedulerBean = context
.getBean(SpringBatchScheduler.class);
await().untilAsserted(() -> Assert.assertEquals(
2,
schedulerBean.getBatchRunCounter().get()));
bean.postProcessBeforeDestruction(
schedulerBean, "SpringBatchScheduler");
await().atLeast(3, SECONDS);

Assert.assertEquals(
2,
schedulerBean.getBatchRunCounter().get());
}

При наличии нескольких планировщиков лучше оставить один планировщик в своем собственном классе, чтобы мы могли останавливать определенный планировщик по мере необходимости.

3.2. Отмена запланированного будущего

Другой способ остановить планировщик — вручную отменить его Future .

Вот настраиваемый планировщик задач для захвата карты будущего :

@Bean
public TaskScheduler poolScheduler() {
return new CustomTaskScheduler();
}

private class CustomTaskScheduler
extends ThreadPoolTaskScheduler {

//

@Override
public ScheduledFuture<?> scheduleAtFixedRate(
Runnable task, long period) {
ScheduledFuture<?> future = super
.scheduleAtFixedRate(task, period);

ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
scheduledTasks.put(runnable.getTarget(), future);

return future;
}
}

Затем мы повторяем карту Future и отменяем Future для нашего планировщика пакетных заданий:

public void cancelFutureSchedulerTasks() {
scheduledTasks.forEach((k, v) -> {
if (k instanceof SpringBatchScheduler) {
v.cancel(false);
}
});
}

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

4. Вывод

В этой быстрой статье мы попробовали три разных способа запуска или остановки запланированного задания Spring Batch.

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

Как обычно, все примеры кода, использованные в статье, доступны на GitHub .