Como acionar e interromper um trabalho em lote agendado da primavera

Como acionar e interromper um trabalho em lote agendado da primavera

1. Visão geral

Neste tutorial, vamos investigar e comparar diferentes maneiras detrigger and stop a scheduled Spring Batch job  para quaisquer casos de negócios necessários.

Se você precisar de introduções sobre Spring Batch and Scheduler, consulte os artigosSpring-BatcheSpring-Scheduler.

2. Disparar um trabalho em lote programado de primavera

Primeiramente, temos uma classeSpringBatchScheduler para configurar o agendamento e o batch job. Um métodolaunchJob() será registrado como uma tarefa agendada.

Além disso, para acionar o trabalho agendado do Spring Batch da maneira mais intuitiva, vamos adicionar um sinalizador condicional para disparar o trabalho apenas quando o sinalizador estiver definido como verdadeiro:

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)

A variávelbatchRunCounter será usada em testes de integração para verificar se o trabalho em lote foi interrompido.

3. Interromper um trabalho em lote agendado da primavera

Com o sinalizador condicional acima, podemos acionar o job agendado do Spring Batch com a tarefa agendada ativa.

Se não precisarmos retomar o trabalho, podemos realmente interromper a tarefa agendada para economizar recursos.

Vamos dar uma olhada em duas opções nas próximas duas subseções.

3.1. Usando o processador posterior do agendador

Como estamos agendando um método usando a anotação@Scheduled, um pós-processador de beanScheduledAnnotationBeanPostProcessor teria sido registrado primeiro.

Podemos chamar explicitamente opostProcessBeforeDestruction() para destruir o bean programado fornecido:

@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());
}

Considerando vários agendadores, é melhor manter um agendador em sua própria classe, para que possamos interromper o agendador específico conforme necessário.

3.2. Cancelando oFuture programado

Outra maneira de parar o planejador seria cancelar manualmente seuFuture.

Aqui está um programador de tarefas personalizado para capturar o mapa deFuture:

@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;
    }
}

Em seguida, iteramos o mapaFuture e cancelamosFuture para nosso agendador de tarefas em lote:

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

Nos casos com várias tarefas do planejador, podemos manter o mapaFuture dentro do pool do planejador personalizado, mas cancelar o correspondenteFuture planejado com base na classe do planejador.

4. Conclusão

Neste artigo, tentamos três maneiras diferentes de acionar ou interromper um trabalho agendado do Spring Batch.

Quando precisamos reiniciar o trabalho em lotes, o uso de um sinalizador condicional para gerenciar a execução do trabalho seria uma solução flexível. Caso contrário, podemos seguir as outras duas opções para parar completamente o planejador.

Como de costume, todos os exemplos de código usados ​​no artigo estão disponíveisover on GitHub.