Idea is not to start job if already same job is running.
JobExplorer is simple injected in class where is scheduled method for running
public class JobClass {
private final Job job;
private final JobExplorer jobExplorer;
private final JobLauncher jobLauncher;
public JobMain(Job job,
JobLauncher jobLauncher,
JobExplorer jobExplorer) {
this.job = job;
this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer;
}
and then it is executed
@Scheduled("0 */5 * ? * *")
public void startJob() {
JobParameters jobParameters = new JobParametersBuilder()
.addString("jobName", String.valueOf(instant.toEpochMilli()))
.toJobParameters();
jobLauncher.run(job, jobParameters);
}
This is not solution because if JVM stopped while job is running this will be same as current job running:
jobExplorer.findRunningJobExecutions("jobName")
It will find all jobs with exitCode ExitStatus.UNKNOWN.
There is 3 solutions as I see it:
Solution 1:
stop previous running not finished jobs and run new job PROS: everything is clean, just one property
CONT: loosing current execution of current job
@Scheduled("0 */5 * ? * *")
public void startJob() {
(JobExecution jobExecution: jobExplorer.findRunningJobExecutions("jobName")) jobExecution.stop();
...
}
Solution 2
Calculate time between latest running job like it is here described and if it is any do not start new job: https://stackoverflow.com/a/23218986/1182625
PROS: everything is clean
CONT: have to have doubled property (5 *60*1000 and "0 */5 * ? * *")
Set<JobExecution> jobExecutions = jobExplorer.findRunningJobExecutions("jobName");
if(jobExecutions.size()>1){
Long currentTime = (new Date()).getTime();
for(JobExecution execution : jobExecutions) {
if((currentTime - execution.getStartTime().getTime()) < 5*60*1000) {
return;
} else {
execution.stop();
}
}
}
Solution 3
Idea is simple to add static (to share between instances of class) volatile (to share between threads) flag which will indicate is any job currently running PROS: just one property
CONT: needs 2 listeners, and volatile static variable which i don't know how reacted in multi-nodes environment
private static volatile boolean FINISHED = true;
and then simple add listener and FINISHED modify method:
// reset FINISHED after job is done
@AfterJob
public void afterJob() {
FINISHED = true;
}
public void setFinished() {
this.FINISHED = true;
}
And simple add:
@Scheduled("0 */5 * ? * *")
public void startJob() {
if(!FINISHED) return;
FINISHED = false;
...
}
And finally add StepListener
public MyStepListener() {
...
@AfterStep
public ExitStatus afterStep(StepExecution stepExecution) {
if(stepExecution.getExitStatus().getExitCode().equalsIgnoreCase(ExitStatus.FAILED.getExitCode())) (new JobMain()).setFinished();
return null;
}