user923499
user923499

Reputation: 343

spring batch retry not working with retrytemplate

I tried the spring batch retry in this example. Retry feature is not working in Spring Batch and it works. I am trying to achieve the same with retrytemplate, but couldn't see the retry not working when thrown exception.

        @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;
          }

        }

Am I missing something when I use RetryTemplate? I tried declarative configuration on step and job methods too, but no luck.

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

Note: using spring-retry 1.2.2 RELEASE.

Upvotes: 1

Views: 2551

Answers (2)

MOURAD404
MOURAD404

Reputation: 11

Thrown exceptions during job execution do not stop the execution, the job continue until it returns the execution result either FAILED OR COMPLETED ... Which makes it a positive result for RetryTemplate.execute(). You can take advantage of the execution status returned to throw a runtimeException in case of failure.

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);
        }
    });

Function: 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;     
}

Upvotes: 1

Mahmoud Ben Hassine
Mahmoud Ben Hassine

Reputation: 31590

The method @Bean public Job job() { ... } is intended to define a Spring Bean of type Job. According to your code, you are calling retryTemplate().execute inside this method and expecting the job to be retried. This is not correct.

What you can try is first define your job like:

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

then call the retry template on the job bean you get from the application context in the main method, something like:

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());
            };
        });
}

If I understand correctly, you are trying to automatically retry a failed job with a retry template, something similar to what is suggested in this PR: https://github.com/spring-projects/spring-batch/pull/440.

Anyway, I hope the example helps.

Upvotes: 0

Related Questions