将 Spring Batch Tasklet 失败消息传递给报告步骤。

Cod*_*kie 1 java spring spring-batch spring-boot

我正在使用带有 OpenCSV 的 Spring Batch Tasklet 来读取我的 CSV 文件。在问这个问题之前,我知道块,但是在后面的步骤中文件之间存在交叉验证,所以我必须继续使用Tasklet。

我要做的是向我的报告步骤报告丢失的文件或解析错误。我不确定向下一步报告失败的正确方法应该是什么。我有以下代码。

读取文件的初始步骤。

public class CsvBatchReader<T> implements Tasklet, StepExecutionListener {

    private final Logger logger = LoggerFactory.getLogger(CsvBatchReader.class);

    private List batch;

    private final Class<T> clazz;

    private Path path;

    public CsvBatchReader(Class<T> clazz, Path path) {
        this.clazz = clazz;
        this.path = path;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        logger.info("Reader initialized - " + clazz.getSimpleName());

        batch = new ArrayList();
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        logger.info("Reader ended - " + clazz.getSimpleName());
        return ExitStatus.COMPLETED;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws UnexpectedJobExecutionException {
        logger.info("Reader execute - " + clazz.getSimpleName());


        ICsvToBean csvToBean = new CsvToBean(clazz, path);

        try {
            batch = csvToBean.readCsv();
        } catch(IOException ex) {
            // error message being caught from my csvToBean class. 
            throw new UnexpectedJobExecutionException("Invalid file " + ex.getMessage());
        }

        return RepeatStatus.FINISHED;
    }

}
Run Code Online (Sandbox Code Playgroud)

报告步骤

我不确定如何传入异常消息,或者是否定义了在不使用 Step Execution Context 的情况下传入失败消息的方法。

public class CsvBatchReporting implements Tasklet, StepExecutionListener {

    private final Logger logger = LoggerFactory.getLogger(CsvBatchCrossValidation.class);

    private List errorMessages;
    private List skippedInserts;

    @Override
    public void beforeStep(StepExecution stepExecution) {
        logger.info("Reporting initialized");

        ExecutionContext executionContext = stepExecution
                .getJobExecution()
                .getExecutionContext();

        System.out.println("description " + stepExecution.getStatus());


    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        logger.info("Reporting ended");
        return ExitStatus.COMPLETED;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        logger.info("Reporting execute");

        //Email Error 

        return RepeatStatus.FINISHED;
    }

}
Run Code Online (Sandbox Code Playgroud)

作业配置

@Bean
public Job primaryCareJob(@Qualifier("reportingStep") Step reportingStep, @Qualifier("crossValidationStep") Step crossValidationStep) {
    logger.info("Start PrimaryCare Job");

    return jobs.get("primaryCareJob")
            .start(readPrimaryCareStep()).on("FAILED").to(reportingStep)
            .from(readPrimaryCareStep()).on("*").to(readPrimaryCareDetailStep())

            .from(readPrimaryCareDetailStep()).on("FAILED").to(reportingStep)
            .from(readPrimaryCareDetailStep()).on("*").to(processPrimaryCareStep())

            .from(processPrimaryCareStep()).on("INVALID").to(reportingStep)
            .from(processPrimaryCareStep()).on("*").to(processPrimaryCareDetailStep())

            .from(processPrimaryCareDetailStep()).on("INVALID").to(reportingStep)
            //Other steps

            .from(reportingStep).on("*").end()
            .from(reportingStep).on("*").fail()

            .build()
        .build();
}
Run Code Online (Sandbox Code Playgroud)

我开始将我的工作模式更改为失败,而不是将其定义为无效以获取异常以自动调用失败的步骤。我使用无效的其他步骤是在我的 afterStep 中使用以下代码定义的。

if(!errorMessages.isEmpty()) {
            chunkContext.getStepContext().getStepExecution().setExitStatus(new ExitStatus("INVALID"));
}
Run Code Online (Sandbox Code Playgroud)

如何从阅读器中获取要传递到我的报告步骤的 CSV 异常消息,以便我可以将其作为电子邮件发送?

Mah*_*ine 6

我不确定如何传入异常消息,或者是否定义了在不使用 Step Execution Context 的情况下传入失败消息的方法。

您可以访问作业执行中上一步抛出的异常。下面是一个例子:

import java.util.List;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
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.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 step1() {
        return steps.get("step1")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("hello");
                    throw new Exception("Boom!");
                })
                .build();
    }

    @Bean
    public Step step2() {
        return steps.get("step2")
                .tasklet((contribution, chunkContext) -> {
                    JobExecution jobExecution = chunkContext.getStepContext().getStepExecution().getJobExecution();
                    StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next(); // TODO properly get the stepExecution of the previous step
                    List<Throwable> failureExceptions = stepExecution.getFailureExceptions();
                    if (!failureExceptions.isEmpty()) {
                        Throwable throwable = failureExceptions.get(0);
                        System.out.println("Looks like step1 has thrown an exception: " + throwable.getMessage());
                    }
                    System.out.println("world");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                    .flow(step1())
                    .on("*").to(step2())
                    .build()
                .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());
    }

}
Run Code Online (Sandbox Code Playgroud)

此示例打印:

hello
Looks like step1 has thrown an exception: Boom!
world
Run Code Online (Sandbox Code Playgroud)

显然,您需要确保在所有情况下 step1 都流向 step2(因此是流定义)。

希望这可以帮助。