在基于块的步骤中中止批处理作业

Aborting a Batch Job during a chunk-based step

我在 Spring 批处理中设置了一个有点线性的作业,它由几个步骤组成。如果在任何时候,单个步骤失败,则作业应该失败。

这些步骤由许多 tasklet 和一个基于块的步骤组成。即:

如果出现问题,显而易见的事情就是抛出异常。 Spring Batch 将处理此问题并记录所有内容。这种行为,尤其是打印堆栈跟踪,是不可取的,如果可以在 Status 设置为 FAILED.

的情况下优雅地结束作业会更好

Tasklet 当前直接在 StepContribution 上设置 ExitStatus。它们也是使用流程构建的(这并不理想,但步骤继续不受阻碍)。然后可以直接在 Tasklet 中处理这些问题。

但是,我们无法访问基于块的方法中的 StepContribution。我们只有 StepExecution。使用 setExitStatus 在这里什么都不做。

我们使用的是构建器(JobBuilerFactoryStepBuilderFactory),而不是 XML 设置。

可能的解决方案:

  1. 告知或配置 Batch 如何处理异常(不打印堆栈跟踪)。
  2. 在侦听器中捕获异常。不幸的是,当它到达 @AfterStep.
  3. 时,异常已经被 Spring 批处理捕获
  4. 告诉 step/job 我们不想继续(例如,在执行上下文中设置一个值或 StepContribution 的替代项。

我认为您可以探索以下两个选项。

选项 1: 您可以使用 noSkip Exception

这显式地防止某些异常(和子类)被跳过 抛出一些您希望作业失败的特定异常。

这是配置帽子的方法

stepBuilderFactory.get("myStep")
                .<POJO, POJO> chunk(1000)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .faultTolerant()
                .noSkip(YourCustomException.class)
                .skip(Exception.class)
                .skipLimit(100) 

****选项 2** :** 您可以将退出状态设置为 FAILED,以便在步骤完成后进入错误流程

public class MyStepExecutionListener implements StepExecutionListener {

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {


    if(allIsGood()) // 
    {
         return ExitStatus.COMPLETED;
    }
    else if (someExceptionOrErrorCase()){   

        return ExitStatus.FAILED;
    }
 }

 }

希望这对您有所帮助

据我所知,停止作业的唯一方法是抛出异常。没有其他优雅的方式来告诉 Spring 批次 "This job is done, it failed, go directly to Failed, do not pass GO, etc."

虽然不是原始问题的直接解决方案,但可以使用 StepBuilder.exceptionHandler() 来更好地控制抛出的异常,例如记录它们。

public class LogAndRethrowExceptionHandler implements ExceptionHandler {
    private static final Logger LOGGER = Logger.getLogger(...);

    @Override
    public void handleException(RepeatContext repeatContext, Throwable throwable) throws Throwable {
        LOGGER.error(throwable.getMessage());
        throw throwable;
    }
}

理论上,这样您可以隐藏 Spring Batch 生成的堆栈跟踪,但仍会显示错误消息。

在我的例子中,我最终添加了条件并在 Reader 和 Processor

中抛出了 JobInterruptedException
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobInterruptedException;

public class CustomReader implements ItemReader<String> {

  @Override
  public String read() throws Exception {
    // ...

    // if ("condition to stop job") {
      throw new JobInterruptedException("Aborting Job", BatchStatus.ABANDONED);
    // }
  }

}