Search code examples
spring-batchspring-batch-tasklet

Repeat tasklet step until certain condition


I used Spring batch to build a ETL job. My main job is simply read from a db and write to another one. Before my main job, I need to check a status in the source db to see if it is ready or not. I will proceed with the main job only if the source db is ready. I implemented the check status logic as a Tasklet and I build my job with the simple logic that if check status step failed repeat this step util the step succeed, then proceed with the main job. I build the job as follows:

@Bean
public Job myJob(MyListener listener) {

    return jobBuilderFactory.get(jobName)
                            .incrementer(new RunIdIncrementer())
                            .listener(listener)
                            .start(checkStatusStep())
                            .on("*").to(mainStep())
                            .on(ExitStatus.FAILED.getExitCode())
                            .to(checkStatusStep())
                            .end()
                            .build();
}

The check status step is a tasklet as follows:

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws InterruptedException {
    //isReady method check the db to see if it is ready
    if (isReady()) {
        //contribution.setExitStatus(ExitStatus.COMPLETED);
        return RepeatStatus.FINISHED;
    } else {
        //contribution.setExitStatus(ExitStatus.FAILED);
        return RepeatStatus.CONTINUABLE;
    }
}

I read the spring batch document and get that the ON method in the conditional follow will check the exit status of the step so that I set the exit status in the StepContribution. What makes me confused is that when I comment those two lines out and the code still works.

So my question is, first, if the conditional flow checks the exit status why my code works without explicitly change the exit status? Second, why tasklet return a repeat status and by whom this repeat status is consumed. Third, is there a better way to achieve my goal?


Solution

  • if the conditional flow checks the exit status why my code works without explicitly change the exit status?

    Because by default if the tasklet returns RepeatStatus.FINISHED, its exit code will be set to COMPLETED

    Second, why tasklet return a repeat status and by whom this repeat status is consumed.

    A tasklet is called repeatedly by the TaskletStep until it either returns RepeatStatus.FINISHED or throws an exception to signal a failure. Each call to a Tasklet is wrapped in a transaction. The structure is therefore that of a loop with transaction boundary inside the loop.

    Third, is there a better way to achieve my goal?

    IMO, your Tasklet implementation is ok as is, you don't need the exit status. Something like:

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws InterruptedException {
       //isReady method check the db to see if it is ready
       if (isReady()) {
        return RepeatStatus.FINISHED;
       } else {
        return RepeatStatus.CONTINUABLE;
       }
    }
    

    This will continuously run until isReady is true, so you don't need to implement the iteration with a flow at the job level. The job definition would be:

    @Bean
    public Job myJob(MyListener listener) {
    
       return jobBuilderFactory.get(jobName)
                            .incrementer(new RunIdIncrementer())
                            .listener(listener)
                            .start(checkStatusStep())
                            .next(mainStep())
                            .build();
    }
    

    Hope this helps.