Spring Batch在集群环境中正确重启未完成的作业

时间:2018-07-28 06:20:13

标签: spring-boot spring-batch high-availability

我使用以下逻辑在单节点Spring Batch应用程序上重新启动未完成的作业:

public void restartUncompletedJobs() {

    try {
        jobRegistry.register(new ReferenceJobFactory(documetPipelineJob));

        List<String> jobs = jobExplorer.getJobNames();
        for (String job : jobs) {
            Set<JobExecution> runningJobs = jobExplorer.findRunningJobExecutions(job);

            for (JobExecution runningJob : runningJobs) {
                runningJob.setStatus(BatchStatus.FAILED);
                runningJob.setEndTime(new Date());
                jobRepository.update(runningJob);
                jobOperator.restart(runningJob.getId());
            }
        }
    } catch (Exception e) {
        LOGGER.error(e.getMessage(), e);
    }
}

现在,我正在尝试使其在两节点群集上运行。每个节点上的两个应用程序都将指向共享的PostgreSQL数据库。

让我们考虑以下示例:我有2个作业实例-jobInstance1正在node1上运行,而jobInstance2正在node2上运行。 Node1执行期间,由于某种原因,jobInstance1重新启动。在node1重新启动后,spring batch应用程序尝试使用上述逻辑重新启动未完成的作业-它看到有2个未完成的作业实例-jobInstance1jobInstance2(正在正确地运行node2),然后尝试重新启动它们。通过这种方式代替重新启动唯一的jobInstance1-它会重新启动jobInstance1jobInstance2 ..但是jobInstance2不应重新启动,因为它现在在{ {1}}。

如何在应用程序启动期间正确地重启未完成的作业(在上一次应用程序终止之前),并防止像node2之类的作业也将重新启动的情况?

已更新

这是下面答案中提供的解决方案:

jobInstance2

我有一个关于#2.1的问题-在应用程序重新启动后,Spring Batch会自动以运行中的执行方式重新启动未完成的作业吗?还是我需要执行手动操作?

1 个答案:

答案 0 :(得分:1)

您的逻辑不会重新启动未完成的作业。您的逻辑是采用当前正在运行的作业执行,将其状态设置为FAILED并重新启动它们。您的逻辑不应找到正在运行的执行,应查找当前正在运行的执行,尤其是失败的执行,然后重新启动。

  

如何正确地重新启动失败的作业并防止像jobInstance2这样的作业也将重新启动的情况?

在伪代码中,您需要执行以下操作:

  1. 通过JobOperator#getJobInstances获取工作的工作实例
  2. 对于每个实例,使用JobOperator#getExecutions检查是否正在运行执行。

    2.1如果正在运行执行,请移至下一个实例(以使执行成功或失败完成)

    2.2如果当前没有正在运行的执行,请检查上一次执行的状态,如果失败则使用JobOperator#restart重新启动。

在您的情况下:

  • jobInstance1应该在步骤2.2中重新启动
  • jobInstance2应该在步骤2.1中进行过滤,因为在节点2上有正在运行的执行。
相关问题