Пакетное задание Spring выполняет дважды один и тот же решающий элемент

Я хочу создать задание с этим потоком:

execute step1
if (resource doesn't exist)
   execute createStep
else
   execute updateStep

Я создал решающее значение для возврата «СОЗДАТЬ» или «ОБНОВИТЬ». Мой решающий элемент определяется с помощью @Service, поэтому bean-компонент будет автоматически подключен

мой рабочий процесс следующий:

return jobs.get("someJobName")
       .start(step1())
       .next(myDecider).on("CREATE").to(createStep())
       .from(myDecider).on("UPDATE").to(updateStep())
       .end().build();

Когда я запускаю свой UnitTest, он выполняет все шаги, создает и обновляет, как будто он запустил решающий второй раз, выбрав оба пути. Что я делаю неправильно?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
0
1 401
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне нравится.

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

Невозможно за один прогон получить системное сообщение для CREATE и UPDATE.

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

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.Random;

@EnableBatchProcessing
@SpringBootApplication
public class DemoApplication {

    @Autowired
    StepBuilderFactory stepBuilderFactory;

    @Autowired
    JobBuilderFactory jobBuilderFactory;

    @Bean
    MyDecider myDecider() {
        return new MyDecider();
    }

    @Bean
    Step stepInit() {
        return stepFactoryWithMessage("stepInit");
    }

    @Bean
    Step createStep() {
        return stepFactoryWithMessage("createStep");
    }

    @Bean
    Step updateStep() {
        return stepFactoryWithMessage("updateStep");
    }

    @Bean
    Job job() {
        return this.jobBuilderFactory.get("job")
                .start(stepInit())
                .next(myDecider()).on("CREATE").to(createStep())
                .from(myDecider()).on("UPDATE").to(updateStep())
                .end()
                .build();
    }

    static class MyDecider implements JobExecutionDecider {
        public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
            String status;
            if (new Random().nextBoolean()) {
                status = "CREATE";
            }
            else {
                status = "UPDATE";
            }
            return new FlowExecutionStatus(status);
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


    private Step stepFactoryWithMessage(String stepName) {
        return this.stepBuilderFactory.get(stepName)
                .tasklet(
                        (StepContribution stepContribution, ChunkContext chunkContext) -> {
                            System.out.println("from " + stepName);
                            return RepeatStatus.FINISHED;
                        }).build();
    }
}

Я поддерживаю этот ответ. Протестировано и работает, как ожидалось, в соответствии с тем, что задано в вопросе.

Mahmoud Ben Hassine 26.10.2018 09:16

Ага. Когда я запускаю загрузочное приложение, оно запускает только один из тасклетов. Это появляется только тогда, когда я запускаю модульные тесты. JobExecution jobExecution = jobLauncherTestUtils.launchJob () Есть подсказки по этому поводу?

Hugo Dias 26.10.2018 10:25
Ответ принят как подходящий

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

Другие вопросы по теме