I wrote a Job of two Steps, with one of two steps being a partitioning step. The partition step uses TaskExecutorPartitionHandler and runs 5 slave steps in threads. The job
I also had difficulty with my partitioned Spring batch application hanging on completion when I used a ThreadPoolTaskExecutor. In addition, I saw that the executor was not allowing the work of all the partitions to finish.
I found two ways of solving those issues.
The first solution is using a SimpleAsyncTaskExecutor instead of a ThreadPoolTaskExecutor. If you do not mind the extra overhead in re-creating threads, this is a simple fix.
The second solution is creating a JobExecutionListener that calls shutdown on the ThreadPoolTaskExecutor.
I created a JobExecutionListener like this:
@Bean
public JobExecutionListener jobExecutionListener(ThreadPoolTaskExecutor executor) {
return new JobExecutionListener() {
private ThreadPoolTaskExecutor taskExecutor = executor;
@Override
public void beforeJob(JobExecution jobExecution) {
}
@Override
public void afterJob(JobExecution jobExecution) {
taskExecutor.shutdown();
}
};
}
and added it to my Job definition like this:
@Bean
public Job partitionedJob(){
return jobBuilders.get("partitionedJob")
.listener(jobExecutionListener(taskExecutor()))
.start(partitionedStep())
.build();
}