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

Как гарантировать, что когда задание выполняется, ему не разрешено запускаться снова в то же время?

У нас есть BJ, которому требуется 1 час для обработки фида и заполнения временных таблиц. Первым шагом этого BJ является очистка временных таблиц и начало заполнения данных из таблиц витрины основного магазина.

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

Поэтому, пожалуйста, предложите, как я могу провести второе выполнение, пока первое не ЗАВЕРШЕНО?


person techanuva    schedule 27.03.2013    source источник
comment
см. мой ответ здесь, чтобы получить представление stackoverflow.com/a/11703889/305142   -  person Serkan Arıkuşu    schedule 27.03.2013


Ответы (7)


Вы можете создать собственный Tasklet в качестве первого шага и используйте JobExecutionDao, чтобы найти все JobExecutions. Если их несколько, работает - генерирует исключение.

person Michail Nikolaev    schedule 27.03.2013
comment
Есть ли способ добиться этого в Partitioner, чтобы это можно было сделать глобально... - person techanuva; 29.04.2013

Я уверен, что это будет не лучшее решение, но, тем не менее, я надеюсь, что это поможет в вашей ситуации.

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

Таким образом, это выдаст ошибку и не позволит вам запустить 2 выполнения одного и того же задания одновременно. Удаление гарантирует, что последовательное выполнение разрешено.

АЛЬТЕРНАТИВНЫЙ МЕТОД: напишите задание с одним параметром job-execution-id. Каждый раз перед выполнением задания запрашивайте максимальное значение job-execution-id для выполненных заданий из пакетных таблиц для задания. Теперь выполните задание с job-execution-id, увеличенным на 1 в качестве входного параметра.

Я думаю, что это лучший метод, чем выше. Я не уверен, предоставляет ли сам Springbatch какие-либо простые варианты реализации этого сценария.

person coder91    schedule 16.07.2013

Возможно, я неправильно истолковал ваш вопрос, но вы можете ограничить количество параллельных выполнений любого отдельного шага, указав throttle-limit в тасклете внутри шага. Указав один, вы должны убедиться, что у вас есть только одно выполнение за раз:

<batch:step id="stepA" next="stepB">
  <batch:tasklet throttle-limit="1">
    <batch:chunk reader="myReader" writer="myWriter" commit-interval="100"/>
  </batch:tasklet>
</batch:step>
person Stefan Haberl    schedule 20.08.2013

Вы можете настроить пользовательский интерфейс spring-batch-Admin для просмотра состояния заданий (сбой/выполняется/завершено и т. д.). При правильной настройке пользовательского интерфейса Spring Batch Admin вы даже можете просматривать статус нескольких задач внутри разных заданий.

person Bharath    schedule 27.03.2013
comment
мы уже настроили Spring Batch Admin. Поэтому, пожалуйста, предложите, как я могу удержать второе выполнение, пока первое не будет ЗАВЕРШЕНО программно. Чтобы выполнение второго задания не начиналось до тех пор, пока не будет завершено первое - person techanuva; 04.04.2013

Реализовать это в рамках одной JVM можно с помощью двоичного семафора. Это поможет избежать параллельного выполнения одного и того же задания. Заставить второй экземпляр ждать будет немного сложно, если вы не хотите, чтобы он просто пропустил выполнение, если установлено значение семафора.

Вы можете выполнить более сложную сериализацию (в том числе на пакетных узлах Spring), используя подходящую реализацию «Выборы лидера». Я использовал Netflix Curator (рецепт Apache Zookeeper) в своем проекте. Некоторые указатели здесь: https://github.com/regunathb/Trooper/wiki/Useful-Batch-Libraries

person Regunath B    schedule 04.06.2013

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

    public class CompletedJobRunIdIncrementer extends RunIdIncrementer {
    private final JobRepository jobRepository;
    private final String jobName;

    public CompletedJobRunIdIncrementer(JobRepository jobRepository, String jobName) {
        this.jobRepository = jobRepository;
        this.jobName = jobName;
    }

    @Override
    public JobParameters getNext(JobParameters parameters) {
        JobExecution lastJobExecution = jobRepository.getLastJobExecution(jobName, parameters);
        return lastJobExecution == null || lastJobExecution.getStatus() == BatchStatus.COMPLETED ? super.getNext(parameters) : parameters;
    }
}

и задание с этим инкрементом:

jobBuilders.get("myJob").incrementer(new CompletedJobRunIdIncrementer(jobRepository, "myJob").start(someTask()).build()
person eldar    schedule 04.01.2019

Вы можете добавить пользовательскую реализацию JobExecutionListener.

Ниже приведен пример реализации слушателя:

    @Component
    public class JobExecutionListener implements JobExecutionListener{


@Autowired
private JobExplorer jobExplorer;


@Override
public void beforeJob(JobExecution jobExecution) {
    int runningJobsCount = jobExplorer.findRunningJobExecutions(jobExecution.getJobInstance().getJobName()).size();
    if(runningJobsCount > 1){
        throw new RuntimeException("There are already active running instances of this job, Please cancel those executions first.");
    }
}

@Override
public void afterJob(JobExecution jobExecution) {

}

}

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

person rdutta    schedule 05.10.2019