我已经使用此方法成功停止了之前步骤中的作业。
public class FirstListener implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
boolean shouldRun = shouldJobRun();
if (!shouldRun) {
// listeners will still work, but any other step logic (reader, processor, writer) will not happen
stepExecution.setTerminateOnly();
stepExecution.setExitStatus(new ExitStatus("STOPPED", "Job should not be run right now."));
LOGGER.warn(duplicate_message);
}
}
为了简洁/清晰,代码经过了精简,但这就是要点。调用 stepExecution.setTerminateOnly()
和 stepExecution.setExitStatus()
足以让 Spring Batch 停止作业并且不执行任何后续步骤。状态已正确记录在 BATCH_JOB_EXECUTION
表中
EXIT_MESSAGE STATUS
org.springframework.batch.core.JobInterruptedException STOPPED
但是,afterStep
方法中的相同方法会被翻转并且无法识别。状态被记录为“已完成”,所有后续步骤都会顺利进行(最终以它们自己可怕的方式失败,因为 afterStep 中的故障检测正在检测故障,因此它们不必这样做)。
public class SecondListener implements StepExecutionListener {
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
if (stepExecution.getExitStatus().getExitCode().equals(ExitStatus.STOPPED.getExitCode())) {
return stepExecution.getExitStatus();
}
if (everythingIsOkay()) {
return stepExecution.getExitStatus();
}
String failureMessage = "Something bad happened.";
LOGGER.error(failureMessage);
ExitStatus exitStatus = new ExitStatus(ExitStatus.FAILED.getExitCode(), failureMessage);
stepExecution.setExitStatus(exitStatus);
stepExecution.setTerminateOnly();
return exitStatus;
}
这是我能想到的唯一问题:两个监听器使用复合监听器处于同一步骤。
@Bean(name = "org.springframework.batch.core.StepExecutionListener-compositeListener")
@StepScope
public StepExecutionListener compositeListener() {
CompositeStepExecutionListener listener = new CompositeStepExecutionListener();
List<StepExecutionListener> listeners = Lists.newArrayList(secondListener());
if (jobShouldHaveFirstListener()) {
listeners.add(0, firstListener()); // prepend; delegates are called in order
}
listener.setListeners(listeners.toArray());
return listener;
}
public Step firstStep() {
return stepBuilderFactory.get("firstStep")
.listener(compositeListener)
// Small batch size for frequency capping, which happens in the writer, before analytics get written
.<Recipient, Recipient>chunk(500)
.reader(rawRecipientInputFileItemReader)
.processor(recipientItemProcessor)
.writer(recipientWriter)
.throttleLimit(2)
.build();
}
@Bean(name = "org.springframework.batch.core.Job-delivery")
public Job deliveryJob() {
return jobs.get("delivery")
.preventRestart()
.start(firstStep)
.next(deliveryStep)
.next(handleSentStep)
.listener(failedCleanupListener)
.build();
}
我还能做些什么来让这个执行正确停止吗?
最佳答案
经过多次实验,我发现以下流程定义将允许从 StepListener 正确停止作业,而无需执行第一步之后的步骤。
return jobs.get("delivery")
.preventRestart()
.listener(failedCleanupListener)
.flow(firstStep)
.next(deliveryStep)
.next(handleSentStep)
.end()
.build();
主要区别是将 start()
更改为 flow()
并添加 FlowBuilder.end()
方法调用到构建器链的末尾。 SimpleJobBuilder
从 .start
方法返回的类不会公开类似的 end()
方法。
我不知道为什么这会对作业执行的内部产生如此大的影响,并且我很乐意为能够阐明实际差异是什么以及为什么的人提供一些积分 使用 SimpleJobBuilder 会忽略该步骤执行状态代码。但我发现了一些有用的东西,这就是现在最重要的。
关于java - 如何从 StepExecutionListener afterStep 方法停止 Spring Batch 作业?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38023018/