我有一个使用Spring batch实现的计划作业。现在,当它完成时,它不会再次启动,因为它被检测为已完成,是否可以在完成后重置其状态?
@Component
class JobScheduler {
@Autowired
private Job job1;
@Autowired
private JobLauncher jobLauncher;
@Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.jobLauncher.run(this.job1, new JobParameters());
}
}
@Configuration
public class Job1Configuration{
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}
}我知道我可以使用时间或id设置作业参数,但这将每15分钟启动一次新的执行。我想重复相同的执行,直到没有错误地完成,然后执行一个新的。
发布于 2021-09-08 00:52:08
您无法重新启动作业,因为您正在通过调用.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()中的end()将作业状态设置为COMPLETE。
相反,您应该通过调用.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).fail()来使作业失败(
或者通过调用.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).stopAndRestart(step1())来停止作业
这些选项将意味着作业状态是FAILED或STOPPED,而不是COMPLETE,这意味着如果您使用相同的JobParameters启动作业,它将在上一次作业执行时重新启动。
请参阅https://docs.spring.io/spring-batch/docs/current/reference/html/step.html#configuringForStop
要以处理重新启动以前的实例或启动新实例的方式启动作业,您可以查看SimpleJobService -batch-admin中的批处理是如何执行的,并根据您的目的稍微修改一下启动方法。这要求您指定一个增量作业参数,该参数用于启动作业的新实例。
@Override
public JobExecution launch(String jobName, JobParameters jobParameters) throws NoSuchJobException,
JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException {
JobExecution jobExecution = null;
if (jobLocator.getJobNames().contains(jobName)) {
Job job = jobLocator.getJob(jobName);
JobExecution lastJobExecution = jobRepository.getLastJobExecution(jobName, jobParameters);
boolean restart = false;
if (lastJobExecution != null) {
BatchStatus status = lastJobExecution.getStatus();
if (status.isUnsuccessful() && status != BatchStatus.ABANDONED) {
restart = true;
}
}
if (job.getJobParametersIncrementer() != null && !restart) {
jobParameters = job.getJobParametersIncrementer().getNext(jobParameters);
}
jobExecution = jobLauncher.run(job, jobParameters);
if (jobExecution.isRunning()) {
activeExecutions.add(jobExecution);
}
} else {
if (jsrJobOperator != null) {
// jobExecution = this.jobExecutionDao
// .getJobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
jobExecution = new JobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
} else {
throw new NoSuchJobException(String.format("Unable to find job %s to launch",
String.valueOf(jobName)));
}
}
return jobExecution;
}发布于 2021-09-08 05:09:16
这是我在所有评论之后想出的解决方案:
@Component
class JobScheduler extends JobSchedulerLauncher {
@Autowired
private Job job1;
@Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.launch(this.job1);
}
}
public abstract class JobSchedulerLauncher {
@Autowired
private JobOperator jobOperator;
@Autowired
private JobExplorer jobExplorer;
public void launch(Job job) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException, NoSuchJobException, NoSuchJobExecutionException, JobExecutionNotRunningException, JobParametersNotFoundException, UnexpectedJobExecutionException {
// Get the last instance
final List<JobInstance> jobInstances = this.jobExplorer.findJobInstancesByJobName(job.getName(), 0, 1);
if (CollectionUtils.isNotEmpty(jobInstances)) {
// Get the last executions
final List<JobExecution> jobExecutions = this.jobExplorer.getJobExecutions(jobInstances.get(0));
if (CollectionUtils.isNotEmpty(jobExecutions)) {
final JobExecution lastJobExecution = jobExecutions.get(0);
if (lastJobExecution.isRunning()) {
this.jobOperator.stop(lastJobExecution.getId().longValue());
this.jobOperator.abandon(lastJobExecution.getId().longValue());
} else if (lastJobExecution.getExitStatus().equals(ExitStatus.FAILED) || lastJobExecution.getExitStatus().equals(ExitStatus.STOPPED)) {
this.jobOperator.restart(lastJobExecution.getId().longValue());
return;
}
}
}
this.jobOperator.startNextInstance(job.getName());
}
}我的工作现在使用了一个增量器,基于这个https://docs.spring.io/spring-batch/docs/current/reference/html/job.html#JobParametersIncrementer
@Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.incrementer(new CustomJobParameterIncrementor())
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}在我的例子中,我的调度程序不会同时启动同一作业的两个实例,所以如果我在这段代码中检测到一个正在运行的作业,这意味着服务器重新启动了该作业,并将其状态保留为已启动,这就是我停止它并放弃它的原因。
发布于 2021-09-08 08:32:05
我认为这里的困难来自于混合调度和可重启性。我会让每个调度执行一个不同的作业实例(例如,通过添加运行时作为识别作业参数)。
现在,如果给定的计划失败,它可以单独重新启动,直到完成,而不会影响后续计划。这可以手动完成,也可以在另一个预定的方法中以编程方式完成。
https://stackoverflow.com/questions/69083064
复制相似问题