title: Spring Batch: Retrying a tasklet using @Retryable and @EnableRetry annotation
body: <p>I have this tasklet which uploads a file to Amazon S3. Now, I want to retry the tasklet execution whenever an <code>AmazonClientException</code> is thrown. I figured using <code>@Retryable</code> annotation will do the job.</p>
  
  <p>Tasklet:</p>
  
  <pre><code>@Component
  @StepScope
  @Retryable(value=AmazonClientException.class, stateful=true, backoff=@Backoff(2000))
  public class S3UploadTasklet extends ArgsSupport implements Tasklet {
  
      @Autowired
      private S3Client s3Client;
  
      @Autowired
      private S3Properties s3Properties;
  
      private static final Logger LOGGER = LoggerFactory.getLogger(S3UploadTasklet.class);
  
      private static final String FILE_EXTENSION = ".gpg";
  
      @Override
      public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
          try {
              String localFilename = getTempOutputFilename() + FILE_EXTENSION;
              String s3Filename = s3Properties.getReportPath() + getS3OutputFilename() + FILE_EXTENSION;
              File f = new File(localFilename);
              if(f.exists()) {
                  LOGGER.info("Uploading " + localFilename + " to s3...");
                  s3Client.upload(localFilename, s3Filename, s3Properties.getBucketName());
                  LOGGER.info("Uploading done!");
              } else {
                  throw new RuntimeException("Encrypted file not found! Encryption process might have failed.");
              }
          } catch(AmazonClientException e) {
              LOGGER.error("Problems uploading to S3. " + e.getMessage(), e);
              throw e;
          } catch(RuntimeException e) {
              LOGGER.error("Runtime error occured. " + e.getMessage(), e);
              throw e;
          }
  
          return RepeatStatus.FINISHED;
      }
  }
  </code></pre>
  
  <p>Job configuration:</p>
  
  <pre><code>@Configuration
  @EnableBatchProcessing
  @EnableRetry
  public class BatchConfiguration {
      @Autowired
      private JobBuilderFactory jobBuilderFactory;
  
      @Autowired
      private Step generateReport;
  
      @Autowired
      private Step encrypt;
  
      @Autowired
      private Step upload;
  
      @Autowired
      private Step cleanUp;
  
      @Bean
      @Transactional(value="appTransactionManager", isolation=Isolation.READ_COMMITTED)
      public Job generateReconJob() {
          return jobBuilderFactory.get("reconJob")
                  .incrementer(new RunIdIncrementer())
                  .start(generateReport)
                      .on("COMPLETED").to(encrypt)
                  .from(generateReport)
                      .on("NOOP").end()
                  .from(generateReport)
                      .on("FAILED").to(cleanUp)
                  .from(encrypt)
                      .on("COMPLETED").to(upload)
                  .from(encrypt)
                      .on("FAILED").to(cleanUp)
                  .from(upload)
                      .on("*").to(cleanUp)
                  .from(cleanUp)
                      .on("*").end()
                  .end()
                  .build();
      }
  }
  </code></pre>
  
  <p>However, it doesn't do what it is supposed to do. The batch job still doesn't retry the tasklet when the exception is thrown.</p>
  
  <p>Any thoughts?</p>
  
  <p>Here's the config also</p>
  
  <pre><code>@Configuration
  public class ReportConfiguration {
     ...
  
     @Autowired
     private S3UploadTasklet s3UploadTasklet;
  
     ...
  
      @Bean
      public Step upload() {
          return stepBuilderFactory.get("upload")
                  .tasklet(s3UploadTasklet)
                  .build();
      }
  }
  </code></pre>