【问题标题】:Aborting a Batch Job during a chunk-based step在基于块的步骤中中止批处理作业
【发布时间】:2018-05-22 22:30:12
【问题描述】:

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

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

  • 步骤 1
    • 小任务 1
  • 步骤 2
    • 小任务 2
  • 步骤 3
    • 读者
    • 处理器
    • 作家

如果出现问题,显而易见的做法是抛出异常。 Spring Batch 将处理此问题并记录所有内容。这种行为,尤其是打印堆栈跟踪,是不可取的,如果可以优雅地结束 Job 并将 Status 设置为 FAILED 会更好。

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

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

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

可能的解决方案:

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

【问题讨论】:

    标签: java spring exception-handling spring-batch chunks


    【解决方案1】:

    据我所知,停止工作的唯一方法是抛出异常。没有其他优雅的方式告诉 Spring Batch “这个工作完成了,它失败了,直接进入 Failed,不要通过 GO 等等。”

    虽然不是对原始问题的直接解决方案,但可以使用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 产生的堆栈跟踪,但仍然显示错误消息。

    【讨论】:

      【解决方案2】:

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

      选项1:您可以使用noSkip 例外

      这明确防止某些异常(和子类)被跳过 抛出一些你想让工作失败的特定异常。

      这是你可以配置帽子的方法

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

      ****Option 2** :** 您可以使用将退出状态设置为FAILED,以便在步骤完成后出现错误流

      public class MyStepExecutionListener implements StepExecutionListener {
      
          @Override
          public ExitStatus afterStep(StepExecution stepExecution) {
      
      
          if(allIsGood()) // 
          {
               return ExitStatus.COMPLETED;
          }
          else if (someExceptionOrErrorCase()){   
      
              return ExitStatus.FAILED;
          }
       }
      
       }
      

      希望对你有帮助

      【讨论】:

      • 感谢您的建议。不幸的是,第一种情况与我们目前的情况相同。如果没有容错,构建器将简单地对所有异常执行noSkip,这是所需的行为。但是,它仍然会打印出堆栈跟踪。在第二个例子中,使用afterStep(你的意思是`@AfterStep注解吗?),整个步骤仍然会完成。我们希望作业在第一个块失败后失败。
      • 对于案例 2 - 您可以使用 ChunkListener 代替 StepExecutionListener。把你的逻辑放在 afterChunk 方法中。 @option 1:我不确定为什么 option1 不适合你。如果抛出 noSkip 中提到的异常,则批处理将自动失败。
      • 无法在 ChunkListener 中更改 ExitStatus。这意味着该步骤根本没有停止。即使您阻止它写入(或您停止块的任何阶段),它也会继续读取/处理。至于noSkip/skip,作业会失败,但我们不想要堆栈跟踪。我们想自己处理。幸运的是,我已经找到了解决方案,但感谢您的帮助。
      • @Druckles,您愿意分享您的解决方案吗?
      • @AndrewCotton 恐怕我的评论具有误导性;我们没有找到 the 解决方案,只是 a 解决方案:我们最终决定使用日志中的堆栈跟踪。但是,我可以发布我们如何从异常处理中获得更多控制权。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-29
      • 2015-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多