Spring-Batch:如何确保作业运行时,不允许同时再次运行

时间:2013-03-27 07:44:42

标签: spring-batch spring-batch-admin

如何确保作业运行时,不允许同时再次运行?

我们有BJ需要1小时来处理Feed并填充临时表。此BJ的第一步是清除临时表并开始从主存储前端表中填充数据。

考虑一个场景,当BJ启动时(第一次运行),如果我们再次启动BJ,它将从第一步中删除临时表中的内容。

那么请建议我如何才能进行第二次执行,直到第一次执行未完成?

7 个答案:

答案 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) {

}

}

如果您已经运行了该作业的任何实例,这会将当前作业启动标记为失败。您可以根据业务需求处理此异常。