【问题标题】:Spring Batch restart functionality not working when using @StepScope使用 @StepScope 时 Spring Batch 重启功能不起作用
【发布时间】:2019-02-04 09:50:03
【问题描述】:

我想使用 Spring Batch (v3.0.9) 重新启动功能,以便当 JobInstance 重新启动时,流程步骤会从最后一个失败的块点向前读取。只要我不对我的myBatisPagingItemReader bean 方法使用@StepScope 注释,我的重启就可以正常工作。
我正在使用@StepScope,以便我可以在我的myBatisPagingItemReader bean 方法@Value("#{jobParameters['run-date']}")) 中进行后期绑定以获取JobParameters 如果我在 myBatisPagingItemReader() bean 方法上使用 @StepScope 注释,则重新启动不起作用,因为它会创建新实例(范围 = 步骤,名称 = scopedTarget.myBatisPagingItemReader)。
如果我使用 stepscope,我的 myBatisPagingItemReader 是否可以从上次失败中设置 read.count 以重新启动工作?

我已经用下面的例子解释了这个问题。

@Configuration
@EnableBatchProcessing
public class BatchConfig {
    @Bean
    public Step step1(StepBuilderFactory stepBuilderFactory,
        ItemReader<Model> myBatisPagingItemReader,
        ItemProcessor<Model, Model> itemProcessor,
         ItemWriter<Model> itemWriter) {

         return stepBuilderFactory.get("data-load")
            .<Model, Model>chunk(10)
            .reader(myBatisPagingItemReader)
            .processor(itemProcessor)
             .writer(itemWriter)
             .listener(itemReadListener())
             .listener(new JobParameterExecutionContextCopyListener())
             .build();
   }
   @Bean
   public Job job(JobBuilderFactory jobBuilderFactory, @Qualifier("step1") 
               Step step1) {
           return jobBuilderFactory.get("load-job")
            .incrementer(new RunIdIncrementer())
            .start(step1)
            .listener(jobExecutionListener())
            .build();
   }
   @Bean
   @StepScope
   public ItemReader<Model> myBatisPagingItemReader(
         SqlSessionFactory sqlSessionFactory,
         @Value("#{JobParameters['run-date']}") String runDate) 
  {
     MyBatisPagingItemReader<Model> reader = new 
     MyBatisPagingItemReader<>();
     Map<String, Object> parameterValues = new HashMap<>();
     parameterValues.put("runDate", runDate);
     reader.setSqlSessionFactory(sqlSessionFactory);
     reader.setParameterValues(parameterValues);
     reader.setQueryId("query");
     return reader;
   }
}

当我对myBatisPagingItemReader() 使用@Stepscope 注释时重新启动示例,读取器正在获取5 条记录,并且我将块大小(提交间隔)设置为3。

作业实例 - 01 - 作业参数 - 01/02/2019。
块 1:
- 进程记录-1
- 进程记录-2
- 进程记录-3
writer - 写入所有 3 条记录
chunk-1 提交成功

块 2:
流程记录-4
进程记录 5 - 抛出和异常
作业完成并设置为“失败”状态

现在使用相同的作业参数重新启动作业。
作业实例 - 01 - 作业参数 - 01/02/2019.
块 1:
流程记录-1
流程记录-2
流程记录-3
writer - 写入所有 3 条记录
chunk-1 提交成功

块 2:
流程记录-4
进程记录 5 - 抛出和异常
作业完成并设置为“失败”状态

myBatisPagingItemReader() bean 方法上的 @StepScope 注释创建了一个新实例,请参见下面的日志消息。
在 scope=step 中创建对象,name=scopedTarget.myBatisPagingItemReader
在 scope=step, name=scopedTarget.myBatisPagingItemReader
中注册的销毁回调 由于它是新实例,它从 start 开始进程,而不是从 chunk-2 开始。

如果我不使用@Stepscope,它会在重新启动的作业步骤设置时从块 2 重新启动 - MyBatisPagingItemReader.read.count=3。

【问题讨论】:

  • 当您使用StepScope并且作业第一次尝试失败时,您能否分享重启前步骤执行上下文中read.count的值?你如何重新开始工作?即使有读取器的新实例,该实例也将使用最后(失败)步骤执行中的read.count 进行初始化,并从那里继续。我看不出是否使用 StepScope 会影响可重启性。

标签: spring-batch


【解决方案1】:

这里的问题是您返回的是 ItemReader 而不是完全限定的类 (MyBatisPagingItemReader) 或至少是 ItemStreamReader。当您使用 Spring Batch 的 step 范围时,我们会创建一个代理以允许后期初始化。代理基于方法的返回类型(在您的情况下为ItemReader)。您遇到的问题是,因为代理是 ItemReader,所以 Spring Batch 不知道您的 bean 也实现了 ItemStream 并且它是 that 启用可重启性的接口。默认情况下,Spring Batch 会自动为您注册所有 ItemStream 类型的 bean(您也可以自己显式注册 bean,但通常不需要)。

为了解决您的问题,以下应该有效(注意返回类型的变化):

   @Bean
   @StepScope
   public MyBatisPagingItemReader<Model> myBatisPagingItemReader(
         SqlSessionFactory sqlSessionFactory,
         @Value("#{JobParameters['run-date']}") String runDate) {

     MyBatisPagingItemReader<Model> reader = 
         new MyBatisPagingItemReader<>();

     Map<String, Object> parameterValues = new HashMap<>();
     parameterValues.put("runDate", runDate);

     reader.setSqlSessionFactory(sqlSessionFactory);
     reader.setParameterValues(parameterValues);
     reader.setQueryId("query");

     return reader;
   }

这就是为什么我建议在可能的情况下,在使用 @Bean 带注释的方法时,您应该返回尽可能具体的类型,以让 Spring 尽可能地提供帮助。

【讨论】:

  • 不使用具体类型阅读器是问题所在。正如建议的那样,我现在使用了具体类型的阅读器,并且重新启动现在工作正常。阅读器现在从最后一个故障点选择最后一个 reader.read.count。我接受这个解决方案。
猜你喜欢
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-13
  • 2016-04-17
  • 2020-09-21
  • 1970-01-01
相关资源
最近更新 更多