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

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

1. обзор

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

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

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

Во-первых, у нас есть класс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 Batch с активным запланированным заданием.

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

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

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

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

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

@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

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

Вот настраиваемый планировщик задач для захвата карты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);
        }
    });
}

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

4. Заключение

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

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

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