I configured step to read and validate data. If any validation fails,I am updating error table(created to track file details) status as failed and reason as validation message(BatchFileDetail is error table in below code). once saved this in DB, immediately I am throwing exception based on error table status
below is my code
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws
Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
if(CBOSConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
}
But data what i saved in error table is getting roll backed. Handling exception leads to proceed with another step but i want to terminate current job with entry in error table. Any help appreciated.
The solution which i found may not best, but as per time being i proceeds with below.
@Bean
public Job fileParserJob() {
return jobBuilderFactory.get("fileParserJob")
.incrementer(new RunIdIncrementer())
.start(validateFileStep())
.next(validateFileStatusStep())
.build();
}
public Step validateFileStep() {
return stepBuilderFactory.get("validateFileStep")
.tasklet(fileTasklet)
.build();
}
public Step validateFileStatusStep() {
return stepBuilderFactory.get("validateFileStatusStep")
.tasklet(validateBatchFileDetailTasklet)
.build();
}
FileTasklet.java
-----------------
@Override
@Transactional(dontRollbackOn=BatchServiceException.class)
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Resource resource = new FileSystemResource(filePath);
BatchFileDetail batchFileDetail = new BatchFileDetail();
batchFileDetail.setFileId(String.valueOf(System.currentTimeMillis()));
batchFileDetail.setFileName(resource.getFilename());
batchFileDetail.setStatus("STARTED");
batchFileDetail.setProcessedOn(new Date());
CommonUtillity.validateBatchResource(resource, StringConstants.FILE_NAME, batchFileDetail);
validateBatchFileDetail(resource.getFile(), batchFileDetail);
batchFileDetailRepository.saveAndFlush(batchFileDetail);
return RepeatStatus.FINISHED;
}
}
ValidateBatchFileDetailTasklet
------------------------------
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
BatchFileDetail batchFileDetail = batchFileDetailRepository.getRecentFailedTransactionStatus(StringConstants.FILE_NAME);
if(StringConstants.FAILED.equals(batchFileDetail.getStatus())) {
throw new BatchServiceException(batchFileDetail.getReason());
}
return RepeatStatus.FINISHED;
}
With this solution, First error table getting updated with failure status and failed reason then transaction commits in one step. In next step fetching recent record based on file name and checking status of fetched record. If it was FAILED
, throwing exception to terminate current job.
In case of status is not FAILED
only, next data has to be processed. If status was FAILED
, we have to terminate current batch job.