春季批处理重试不适用于retrytemplate

时间:2018-10-14 17:17:47

标签: spring spring-boot spring-batch batch-processing

在此示例中,我尝试了Spring Batch重试。 Retry feature is not working in Spring Batch,它可以正常工作。 我正在尝试使用retrytemplate实现相同的功能,但是在抛出异常时看不到重试不起作用。

        @Configuration
            @EnableBatchProcessing
        //@EnableRetry
        public class RetryBatchJob {

          @Autowired
          private JobBuilderFactory jobs;

          @Autowired
          private StepBuilderFactory steps;

          @Bean
          public ItemReader<Integer> itemReader() {
            return new ListItemReader<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
          }

          @Bean
          public ItemWriter<Integer> itemWriter() {
            return items -> {
              for (Integer item : items) {
                System.out.println("item = " + item);
                if (item.equals(7)) {
                  throw new Exception("Sevens are sometime nasty, let's retry them");
                }
              }
            };
          }

          @Bean
          public Step step() {
            return steps.get("step")
              .<Integer, Integer>chunk(2)
              .reader(itemReader())
              .writer(itemWriter())
              /*.faultTolerant()
              .retryLimit(5)
              .retry(Exception.class)*/
              .build();
          }

          @Bean  
          public Job job() {
            Job job = null;
            try {
              job = retryTemplate().execute(new RetryCallback<Job, Throwable>() {
                @Override
                public Job doWithRetry(RetryContext context) throws Throwable {
                  return jobs.get("job")
                    .start(step())
                    .build();
                }
              });
            } catch (Throwable throwable) {
              throwable.printStackTrace();
            }
            return job;
          }

          public static void main(String[] args) throws Exception {
            ApplicationContext context = new AnnotationConfigApplicationContext(RetryBatchJob.class);
            JobLauncher jobLauncher = context.getBean(JobLauncher.class);
            Job job = context.getBean(Job.class);
            jobLauncher.run(job, new JobParameters());
          }

          @Bean
          public RetryTemplate retryTemplate() {
            RetryTemplate retryTemplate = new RetryTemplate();

            SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(5, singletonMap(Exception.class, true));
            retryPolicy.setMaxAttempts(5);
            retryTemplate.setRetryPolicy(retryPolicy);

            return retryTemplate;
          }

        }

使用RetryTemplate时是否缺少某些东西?我也尝试过在步骤和作业方法上进行声明式配置,但是没有运气。

@Retryable(value = {Exception.class},
 maxAttemptsExpression = "5"
)

注意:使用spring-retry 1.2.2 RELEASE。

2 个答案:

答案 0 :(得分:0)

方法@Bean public Job job() { ... }用于定义类型Job的Spring Bean。根据您的代码,您正在此方法内调用retryTemplate().execute,并期望重试该作业。这是不正确的。

您可以尝试的是先定义您的工作,例如:

@Bean  
public Job job() {
    return jobs.get("job")
                .start(step())
                .build();
}

然后在main方法中调用从应用程序上下文获得的作业bean上的重试模板,类似:

public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(RetryBatchJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        RetryTemplate retryTemplate = context.getBean(RetryTemplate.class);
        retryTemplate.execute(new RetryCallback<JobExecution, Exception>() {
            @Override
            public JobExecution doWithRetry(RetryContext context) throws Exception {
                return jobLauncher.run(job, new JobParameters());
            };
        });
}

如果我理解正确,您正在尝试使用重试模板自动重试失败的作业,类似于此PR中的建议:https://github.com/spring-projects/spring-batch/pull/440

无论如何,我希望该示例对您有所帮助。

答案 1 :(得分:0)

作业执行过程中引发的异常不会停止执行,作业将继续执行,直到返回执行结果为FAILED或COMPLETED ...,这使其成为RetryTemplate.execute()的肯定结果。 您可以利用返回的执行状态在发生故障的情况下引发runtimeException。

RetryTemplate template = new RetryTemplate();

    ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
    exponentialBackOffPolicy.setInitialInterval(5000);
    exponentialBackOffPolicy.setMultiplier(ExponentialBackOffPolicy.DEFAULT_MULTIPLIER);
    exponentialBackOffPolicy.setMaxInterval(ExponentialBackOffPolicy.DEFAULT_MAX_INTERVAL);

    Map<Class<? extends Throwable>, Boolean> exceptions = new HashMap<>();
    exceptions.put(Exception.class, true);
    SimpleRetryPolicy policy = new SimpleRetryPolicy(3, exceptions);

    template.setRetryPolicy(policy);
    template.setBackOffPolicy(exponentialBackOffPolicy);

    template.execute(new RetryCallback<JobExecution, Exception>() {

        @Override
        public JobExecution doWithRetry(RetryContext context) throws Exception {        
            return runJob(job, paramMap);
        }
    });

函数:runJob()

public JobExecution runJob(Job job, Map<String, JobParameter> paramMap) throws Exception {
    JobExecution exe = jobLauncher.run(job, new JobParameters(paramMap));       
    if(exe.getStatus().equals(BatchStatus.FAILED))
        throw new RuntimeException(exe.toString());
    return exe;     
}