【发布时间】:2020-06-01 15:01:25
【问题描述】:
如果已经有相同的作业正在运行,建议不要开始作业。
JobExplorer 被简单地注入到计划运行方法的类中
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;
}
然后执行
@Scheduled("0 */5 * ? * *")
public void startJob() {
JobParameters jobParameters = new JobParametersBuilder()
.addString("jobName", String.valueOf(instant.toEpochMilli()))
.toJobParameters();
jobLauncher.run(job, jobParameters);
}
这不是解决方案,因为如果 JVM 在作业运行时停止,这将与当前作业运行相同:
jobExplorer.findRunningJobExecutions("jobName")
它将找到所有带有 exitCode ExitStatus.UNKNOWN 的作业。
我认为有 3 个解决方案:
解决方案 1:
停止之前运行的未完成作业并运行新作业 优点:一切都很干净,只有一个属性
CONT:失去当前作业的当前执行
@Scheduled("0 */5 * ? * *")
public void startJob() {
(JobExecution jobExecution: jobExplorer.findRunningJobExecutions("jobName")) jobExecution.stop();
...
}
解决方案 2
计算最近运行的作业之间的时间,如这里所述,如果有,请不要开始新作业: https://stackoverflow.com/a/23218986/1182625
优点:一切都很干净
CONT:必须有双倍属性(5 *60*1000 和 "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();
}
}
}
解决方案 3
添加静态(在类实例之间共享)易失(在线程之间共享)标志很简单,这将指示当前正在运行的任何作业 优点:只有一个属性
CONT:需要 2 个侦听器和 volatile 静态变量,我不知道它在多节点环境中的反应如何
private static volatile boolean FINISHED = true;
然后简单的添加监听器和FINISHED修改方法:
// reset FINISHED after job is done
@AfterJob
public void afterJob() {
FINISHED = true;
}
public void setFinished() {
this.FINISHED = true;
}
简单的加法:
@Scheduled("0 */5 * ? * *")
public void startJob() {
if(!FINISHED) return;
FINISHED = false;
...
}
最后添加 StepListener
public MyStepListener() {
...
@AfterStep
public ExitStatus afterStep(StepExecution stepExecution) {
if(stepExecution.getExitStatus().getExitCode().equalsIgnoreCase(ExitStatus.FAILED.getExitCode())) (new JobMain()).setFinished();
return null;
}
【问题讨论】:
标签: spring-batch