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());
}
}
}