lebowski
lebowski

Reputation: 1051

Using listeners to catch errors in steps in Spring Batch

I am new to Spring and Spring Batch. I wrote a basic job that's supposed to repeat every 5 seconds. It has two steps, the first of which (step1) is supposed to fail every time. My aim was to see if the job would report these errors in step1 and continue to step2. The approach I am using to catch errors in step1 is below (using listeners). I would like some critique on how right/wrong my approach is.

This is my job configuration. It has one job which has two steps:

@Configuration
public class JobConfig {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private JobRepository jobRepository;

    @Autowired
    private StepExecutionListenerImpl stepExecutionListener;

    @Bean
    public Step step1() {
        return stepBuilderFactory.get("step1")
                .listener(this.stepExecutionListener)
                .tasklet(new Tasklet() throws Exception {
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        throw new Exception("Step1 caused an exception");
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public Step step2() {
        return stepBuilderFactory.get("step2")
                .tasklet(new Tasklet() {
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws InterruptedException {
                        System.out.println("Step2 is executing");
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }

    @Bean
    public Job job() throws Exception {
        return jobBuilderFactory.get("job")
                .incrementer(new RunIdIncrementer())
                .start(step1())
                .on("COMPLETED").to(step2()).end()
                .build();
    }

    @Scheduled(cron = "*/5 * * * * *")
    public void runJob() throws Exception {

        System.out.println("Job Started at :" + new Date());

        JobParameters param = new JobParametersBuilder().addString("JobID", String.valueOf(System.currentTimeMillis()))
                .toJobParameters();

        JobExecution execution = jobLauncher.run(job(), param);

        System.out.println("Job finished with status :" + execution.getStatus());
    }

   @Bean
    public JobLauncher getJobLauncher() {
       SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
       simpleJobLauncher.setJobRepository(this.jobRepository);
       return simpleJobLauncher;
    }
}

To cause an error in step1, I threw an exception in that step. I also added a listener in step1 whose afterStep() method checks if any exceptions have occurred in that step, and if so, returns ExitStatus.FAILED. If no exceptions occur, it returns ExitStatus.COMPLETED. Below is the code for that:

@Component
public class StepExecutionListenerImpl implements StepExecutionListener {

    @Override
    public void beforeStep(StepExecution stepExecution) {
        System.out.println("Before starting step");
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        List<Throwable> exceptions = stepExecution.getFailureExceptions();
        if(exceptions.isEmpty()) {
            return ExitStatus.COMPLETED;
        } else {
            System.out.println("This step has encountered exceptions");
            exceptions.forEach(th -> System.out.println("Exception has occurred in job"));
            return ExitStatus.FAILED;
        }
    }
}

This seems to be working, since step1 fails on each iteration of the job, and then a new iteration begins. So my question is, is this a good way of catching errors in Spring Batch jobs? Am I using listeners correctly?

Upvotes: 0

Views: 9625

Answers (1)

amdg
amdg

Reputation: 2239

We have implemented ItemReadListener,ItemProcessListener,ItemWriteListener interfaces which contains methods like onReadError,onProcessError,onWriteError. These methods are invoked if there is any exception during the process of reading/processing/writing the records.

Upvotes: 1

Related Questions