Spring RetryTemplate execute retry only on specific type of response (not on an exception)

3.6k views Asked by At

Background: I am calling a REST API to download a text file from a spring boot app. The problem is that the server takes time to generate the file and then make it ready for download.

So, I am using RetryTemplate to wait for 1 minute and attempt 60 times (60 attempts in 1 hour). When the download file is not ready, the server response will be empty, but when the download file is ready, the server will respond with the file URL.

Problem: Now the problem is, the way I've configured RetryTemplate, it'll keep calling the API even if there is an exception from the server.

Desired behavior: RetryTemplate should retry calling the API only when the server response is EMPTY and should NOT retry if the server response contains the download file URL or on a server-side exception.

RetryTemplate bean configuration:

    @Bean
    public RetryTemplate retryTemplate() {
        final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(60);

        final FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(60000L);

        final RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        return retryTemplate;
    } 

Service class method where it's used:

@Override
    public DownloadResult getDownloadFile(final int id) {
            
        // retry for 1 hour to download the file. Call to EBL will be made every minute for 60 minutes until the file is ready
        final DownloadResult result = retryTemplate.execute(downloadFile -> dataAccess.getFile(id));
   
        final InputStream inputStream = Try.of(result::getFileUrl)
                                           .map(this::download)
                                           .onFailure(throwable -> log.error("MalformedURLException: {}", result.getFileUrl()))
                                           .get();

        return result.toBuilder().downloadFileInputStream(inputStream).build();
    }

The server response when download file is ready for download looks like this:

{
    fileUrl:"www.download.com/fileId"
}

Empty server response if download file is not ready for download:

{
}

Thanks in advance for your help!

1

There are 1 answers

0
Gary Russell On

spring-retry is entirely based on exceptions. You need to check the result within the lambda and throw an exception...

retryTemplate.execute(downloadFile -> {
    DownloadResult result = dataAccess.getFile(id));
    if (resultIsEmpty(result)) {
         throw new SomeException();
    }
    return result;
}