如何确保作业运行时,不允许同时再次运行?
我们有BJ需要1小时来处理Feed并填充临时表。此BJ的第一步是清除临时表并开始从主存储前端表中填充数据。
考虑一个场景,当BJ启动时(第一次运行),如果我们再次启动BJ,它将从第一步中删除临时表中的内容。
那么请建议我如何才能进行第二次执行,直到第一次执行未完成?
答案 0 :(得分:3)
您可以创建自定义Tasklet作为第一步,并使用JobExecutionDao查找所有JobExecutions。如果有多个running - 抛出异常。
答案 1 :(得分:1)
我相信,这不是最佳解决方案,但我希望这会为您的情况服务。
执行作业时,请确保使用始终相同的参数运行作业。成功执行作业完成后,配置调用脚本以删除与批处理作业执行相对应的条目。
这样,它会产生错误,并且不允许您同时运行同一作业的2次执行。删除将确保允许串行执行。
替代方法:
使用单个参数job-execution-id
编写您的工作。每次执行作业之前,从作业的批处理表中查询已完成作业的job-execution-id
的最大值。现在,以job-execution-id
递增1作为输入参数执行作业。
我认为这是比上面更好的方法。我不确定,如果springbatch本身为实现这种情况提供了任何简单的选择。
答案 2 :(得分:1)
也许我误解了您的问题,但您可以通过在步骤中指定Tasklet上的throttle-limit
来限制任何单个步骤的并行执行次数。指定一个应确保一次只执行一次:
<batch:step id="stepA" next="stepB">
<batch:tasklet throttle-limit="1">
<batch:chunk reader="myReader" writer="myWriter" commit-interval="100"/>
</batch:tasklet>
</batch:step>
答案 3 :(得分:0)
您可以设置spring-batch-Admin UI以查看作业的状态(失败/运行/完成等)。通过正确设置Spring Batch Admin UI,您甚至可以查看不同作业中的多个任务的状态。
答案 4 :(得分:0)
在单个JVM中实现它应该可以使用二进制信号量来实现。这有助于避免同时执行相同的作业。如果你不希望它设置信号量值,那么让第二个实例等待将会有点棘手。
您可以使用合适的“Leader Election”实现执行更复杂的序列化(包括跨Spring批处理节点)。我在我的项目中使用过Netflix Curator(Apache Zookeeper配方)。这里有一些指示:https://github.com/regunathb/Trooper/wiki/Useful-Batch-Libraries
答案 5 :(得分:0)
我通过编写特殊的增量器来做到这一点,该增量器仅在先前的作业执行完成时才对属性进行增量。
public class CompletedJobRunIdIncrementer extends RunIdIncrementer {
private final JobRepository jobRepository;
private final String jobName;
public CompletedJobRunIdIncrementer(JobRepository jobRepository, String jobName) {
this.jobRepository = jobRepository;
this.jobName = jobName;
}
@Override
public JobParameters getNext(JobParameters parameters) {
JobExecution lastJobExecution = jobRepository.getLastJobExecution(jobName, parameters);
return lastJobExecution == null || lastJobExecution.getStatus() == BatchStatus.COMPLETED ? super.getNext(parameters) : parameters;
}
}
和带有此增量器的作业:
jobBuilders.get("myJob").incrementer(new CompletedJobRunIdIncrementer(jobRepository, "myJob").start(someTask()).build()
答案 6 :(得分:0)
您可以添加JobExecutionListener的自定义实现。
下面是示例侦听器实现:
@Component
public class JobExecutionListener implements JobExecutionListener{
@Autowired
private JobExplorer jobExplorer;
@Override
public void beforeJob(JobExecution jobExecution) {
int runningJobsCount = jobExplorer.findRunningJobExecutions(jobExecution.getJobInstance().getJobName()).size();
if(runningJobsCount > 1){
throw new RuntimeException("There are already active running instances of this job, Please cancel those executions first.");
}
}
@Override
public void afterJob(JobExecution jobExecution) {
}
}
如果您已经运行了该作业的任何实例,这会将当前作业启动标记为失败。您可以根据业务需求处理此异常。