У меня следующая работа:
@Bean
fun createCsvJob(
jobs: JobBuilderFactory,
validateCsvHeaderStep: Step,
processCsvStep: Step,
moveCsvStep: Step,
markCsvAsFailedStep: Step,
moveFailedCsvStep: Step
) = jobs.get(PROCESS_CSV_JOB)
.start(validateCsvHeaderStep)
.next(processCsvStep)
.on("*").to(decider())
.from(decider()).on(ExitStatus.COMPLETED.exitCode).to(moveCsvStep)
.from(decider()).on(ExitStatus.FAILED.exitCode).to(markCsvAsFailedStep).next(moveFailedCsvStep)
.build()
.build()!!
Есть два шага, которые могут привести к сбою validateCsvHeaderStep и processCsvStep. Я хотел бы иметь поток, когда ошибка в обработке перейдет в markCsvAsFailedStep и moveFailedCsvStep, но когда все работает нормально, она должна перейти в moveCsvStep.
В настоящее время, если validateCsvHeaderStep выходит из строя, вся работа терпит неудачу.
Когда я пытаюсь добавить решающий элемент вот так:
.start(validateCsvHeaderStep)
.on(ExitStatus.FAILED.exitCode).to(decider())
.on(ExitStatus.COMPLETED.exitCode).to(processCsvStep)
.on("*").to(decider())
.from(decider()).on(ExitStatus.COMPLETED.exitCode).to(moveCsvStep)
.from(decider()).on(ExitStatus.FAILED.exitCode).to(markCsvAsFailedStep).next(moveFailedCsvStep)
Я получаю:
Next state not found in flow=myJob for state=myJob.validateCsvStep with exit status=COMPLETED
Есть ли способ добиться обработки ошибок на обоих этапах без дублирования логики?
Вам необходимо определить поток, начиная с validateCsvHeaderStep и заканчивая решающим устройством на COMPLETED, как показано ниже:
.start(validateCsvHeaderStep)
.on(ExitStatus.COMPLETED.exitCode).to(processCsvStep)
.from(validateCsvHeaderStep)on("*").to(decider())
here are two steps that can fail validateCsvHeaderStep and processCsvStep. I would like to have a flow when error in processing will go to markCsvAsFailedStep and moveFailedCsvStep, but when everything works fine it should go to moveCsvStep.
Вот пример:
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
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.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class MyJob {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public Step validateCsvHeaderStep() {
return steps.get("validateCsvHeaderStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("validateCsvHeaderStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step processCsvStep() {
return steps.get("processCsvStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("processCsvStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step markCsvAsFailedStep() {
return steps.get("markCsvAsFailedStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("markCsvAsFailedStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step moveFailedCsvStep() {
return steps.get("moveFailedCsvStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("moveFailedCsvStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Step moveCsvStep() {
return steps.get("moveCsvStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("moveCsvStep");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Job job() {
return jobs.get("job")
.flow(validateCsvHeaderStep())
.on(ExitStatus.FAILED.getExitCode()).to(markCsvAsFailedStep())
.from(validateCsvHeaderStep()).on("*").to(processCsvStep())
.from(processCsvStep()).on(ExitStatus.FAILED.getExitCode()).to(markCsvAsFailedStep())
.from(processCsvStep()).on("*").to(moveCsvStep())
.from(markCsvAsFailedStep()).on("*").to(moveFailedCsvStep())
.from(moveFailedCsvStep()).end()
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
он печатает:
validateCsvHeaderStep
processCsvStep
moveCsvStep
Если, например, validateCsvHeaderStep не работает:
@Bean
public Step validateCsvHeaderStep() {
return steps.get("validateCsvHeaderStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("validateCsvHeaderStep");
chunkContext.getStepContext().getStepExecution().setExitStatus(ExitStatus.FAILED);
return RepeatStatus.FINISHED;
})
.build();
}
Он печатает:
validateCsvHeaderStep
markCsvAsFailedStep
moveFailedCsvStep
Если processCsvStep не работает:
@Bean
public Step processCsvStep() {
return steps.get("processCsvStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("processCsvStep");
chunkContext.getStepContext().getStepExecution().setExitStatus(ExitStatus.FAILED);
return RepeatStatus.FINISHED;
})
.build();
}
он печатает:
validateCsvHeaderStep
processCsvStep
markCsvAsFailedStep
moveFailedCsvStep
Надеюсь это поможет.