2

Before raising the question I went through many links like : How can you restart a failed spring batch job and let it pick up where it left off? and Spring Batch restart uncompleted jobs from the same execution and step and https://learning.oreilly.com/library/view/the-definitive-guide/9781484237243/html/215885_2_En_6_Chapter.xhtml, but this doesn't solved my query yet.

I am using Spring Boot Batch application, in my project I've 3 Jobs which runs sequentially on scheduled basis daily 2 PM in the night wrapped up in a single method and each jobs has 5 steps which performs chunk-based processing does not use tasklet.

I often see an issues like network fluctuations, database is down and abnormal issues spring batch is sopping a while job and getting a lot of issues of data loss since there is no way to automatically restart from where if failed.

I want to developed ability to automatically restart the batch jobs when any type of abnormal exceptions arises. Is there any way if we can do that ?

I've configured batch jobs like below.

MyApplication.java

@SpringBootApplication
@EnableBatchProcessing
@EnableScheduling
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

MyJob.java

@Configuration
public class MyJob {

    @Value("${skip.limit}")
    private Integer skipLimit;

    @Value("${chunk.size}")
    private Integer chunkSize;   

    @Bean(name="myJobCache")
    public CacheManager myJobCache() {
        return new ConcurrentMapCacheManager();
    }

    @Bean("customerJob")
    public Job customerJob(JobBuilderFactory jobBuilderFactory,
            StepBuilderFactory stepBuilderFactory,
            JdbcCursorItemReader<Customer> customerReader,
            JdbcCursorItemReader<Department> departmentReader,
            JdbcCursorItemReader<Stock> stockItemReader,
            JdbcCursorItemReader<Advisory> advisoryItemReder) throws Exception {

        return jobBuilderFactory.get("customerJob")
                .incrementer(new RunIdIncrementer())
                .start(customerStep(stepBuilderFactory, customerReader))
                .next(departmentStep(stepBuilderFactory, departmentReader))
                .next(stackStep(stepBuilderFactory))
                .......
                .......
                .......
                .listener(customerListener())
                .build();
    }

    @Bean
    public Step customerStep(StepBuilderFactory stepBuilderFactory,
            JdbcCursorItemReader<Customer> customerReader) {
        return stepBuilderFactory.get("customerStep").
                <Customer, NewCustomer>chunk(chunkSize)
                .reader(customerReader)
                .processor(customerProcessor())
                .writer(customerWriter())
                .faultTolerant()
                .skip(Exception.class)
                .skipLimit(skipLimit)
                .listener(customerSkipListener())
                .listener(customerStepListener())
                .build();
    }

    @Bean
    public CustomerProcessor customerProcessor() {
        return new CustomerProcessor(myJobCache());
    }
    
    @Bean
    public CustomerWriter customerWriter() {
        return new CustomerWriter();
    }
    
    // Like this all other jobs are configured
}

MyScheduler.java

public class MyScheduler {

    @Autowired
    private JobLauncher customerJobLauncher;
    
    @Autowired
    private JobLauncher abcJobLauncher;
    
    @Autowired
    private JobLauncher xyzJobLauncher;

    @Autowired
    @Qualifier(value = "customerJob")
    private Job customerJob;
    
    @Autowired
    @Qualifier(value = "abcJob")
    private Job abcJob;
    
    @Autowired
    @Qualifier(value = "xyzJob")
    private Job xyzJob;

    @Scheduled(cron = "0 0 */1 * * *") // run at every hour for testing 
    public void handle() {
        JobParameters params = new JobParametersBuilder()
                .addString("cust.job.id", String.valueOf(System.currentTimeMillis()))
                .addDate("cust.job.date", new Date()).toJobParameters();
        long diff = 0;
        try {
            JobExecution jobExecution = customerJobLauncher.run(customerJob, params);
            Date start = jobExecution.getCreateTime();

            
            JobParameters job2Params = new JobParametersBuilder()
                    .addString("abc.job.id", String.valueOf(System.currentTimeMillis()))
                    .addDate("abc.job.date", new Date()).toJobParameters();
            
            JobExecution job2Execution = abcJobLauncher.run(abcJob, job2Params);            
            
            JobParameters job3Params = new JobParametersBuilder()
                    .addString("xyz.job.id", String.valueOf(System.currentTimeMillis()))
                    .addDate("xyx.job.date", new Date()).toJobParameters();
            
            JobExecution job3Execution = xyzJobLauncher.run(xyzJob, job3Params);
            
            Date end = job3Execution.getEndTime();
            diff = end.getTime() - start.getTime();

            log.info(JobExecutionTimeCalculate.getJobExecutionTime(diff));
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
                | JobParametersInvalidException e) {
            log.error("Job Failed : " + e.getMessage());
        }
    }
}
Jeff Cook
  • 7,956
  • 36
  • 115
  • 186

0 Answers0