手动更改Spring Batch元数据表是不是一个坏主意?

背景

我正在使用Spring Batch 2.1.8,并通过CommandLineJobRunner运行作业。 如:

 java org.springframework.batch.core.launch.support.CommandLineJobRunner classpath:launchContext.xml theJobId 

问题

在某些情况下,例如服务器崩溃,可能会中断正在运行的作业。 但中断的作业在Spring Batch Meta-Data表中保持STARTED状态,无法再次运行。

 org.springframework.batch.core.repository.JobExecutionAlreadyRunningException: A job execution for this job is already running 

我可以想到两个解决方案:

解决方法1

添加一个新的作业参数并每次更改它以使其成为Spring Batch的“新”作业。 如:

 java org.springframework.batch.core.launch.support.CommandLineJobRunner classpath:launchContext.xml theJobId times=0 

当需要重新运行它时,请清除所有相应的输出数据,计算一次,然后重新运行作业。

溶液2

手动更改Spring Batch元数据表。

更新状态以使作业可重新启动。 如:

 UPDATE BATCH_JOB_EXECUTION SET END_TIME = SYSTIMESTAMP, STATUS = 'FAILED', EXIT_CODE = 'FAILOVER' WHERE JOB_EXECUTION_ID = (SELECT MAX(JOB_EXECUTION_ID) FROM BATCH_JOB_EXECUTION WHERE JOB_INSTANCE_ID = (SELECT MAX(JOB_INSTANCE_ID) FROM BATCH_JOB_INSTANCE WHERE JOB_NAME = 'XXX')); 

我试过了,看起来效果很好。

Solution2是个坏主意吗? 有陷阱吗?

提前致谢。 并且赞赏任何其他解决方案。

解决方案2现在是公认的方法。 API不提供修复此方案的方法。 过去曾有人要求框架自动清理,但99%的情况下,需要人为的决定来确定是否确实需要进行清理。

我对选项2的唯一注意事项是检查BATCH_STEP_EXECUTION表,以查看最后执行步骤的状态。

我为此创建了一个特定的spring bean,它在容器刷新时启动(在app(re)启动时也会发生)。

它搜索“正在运行”的作业,将它们标记为“FAILED”并重新启动它们。

 import java.util.Date; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobOperator; import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class BatchJobRestarter implements ApplicationListener { private static final Logger LOGGER = LoggerFactory.getLogger(BatchJobRestarter.class); @Autowired private JobExplorer jobExplorer; @Autowired JobRepository jobRepository; @Autowired JobOperator jobOperator; @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { LOGGER.info("Container restart: restarting 'running' batch jobs"); List jobs = jobExplorer.getJobNames(); for (String job : jobs) { Set runningJobs = jobExplorer.findRunningJobExecutions(job); for (JobExecution runningJob : runningJobs) { try { LOGGER.info("Restarting job {} with parameters {}", runningJob.getJobInstance().getJobName(), runningJob.getJobParameters().toString()); runningJob.setStatus(BatchStatus.FAILED); runningJob.setEndTime(new Date()); jobRepository.update(runningJob); jobOperator.restart(runningJob.getId()); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } } } } 

Steef