Spring Batch: повторная попытка запуска тасклета с использованием аннотаций @Retryable и @EnableRetry

У меня есть этот тасклет, который загружает файл в Amazon S3. Теперь я хочу повторить выполнение тасклета всякий раз, когда выдается AmazonClientException. Я решил, что аннотация @Retryable подойдет.

Тасклет:

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

Конфигурация работы:

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

Однако он не делает того, что должен делать. Пакетное задание по-прежнему не повторяет выполнение тасклета при возникновении исключения.

Какие-нибудь мысли?

Вот еще конфиг

@Configuration
public class ReportConfiguration {
   ...

   @Autowired
   private S3UploadTasklet s3UploadTasklet;

   ...

    @Bean
    public Step upload() {
        return stepBuilderFactory.get("upload")
                .tasklet(s3UploadTasklet)
                .build();
    }
}

person makalshrek    schedule 03.04.2016    source источник
comment
когда вы говорите, что он не повторяется, что происходит, когда выдается исключение?   -  person Michael Pralow    schedule 03.04.2016
comment
@MichaelPralow Я вижу, что возникает исключение, но затем оно просто переходит к следующему шагу.   -  person makalshrek    schedule 04.04.2016
comment
Я не считаю, что аннотация повторной попытки должна быть расположена на самом Tasklet. Скорее я бы поместил вызов Amazon в его собственный метод и использовал бы там retryable.   -  person IcedDante    schedule 08.05.2016


Ответы (1)


Аннотация @Retryable(value=AmazonClientException.class, stateful=true, backoff=@Backoff(2000)) должна относиться к методу, который вы хотите повторить, а не к классу.

person ufdeveloper    schedule 15.06.2016
comment
Повторная попытка аннотация имеет @Target(value={METHOD,TYPE}), поэтому она может быть в методе/классе/интерфейсе. Аннотирование класса с помощью @Retryable аналогично аннотированию всех методов в классе. Поэтому, если у вас есть общая конфигурация повтора для всех методов в вашем классе, аннотируйте класс/интерфейс. И метод здесь относится к общедоступным методам, поскольку Retryable реализован с использованием Spring AOP. - person Chacko Mathew; 14.03.2017