1

I am calling a third party rest API, some times it sends response with status code 500, 504.
I want to make a another hit to the API if it gives above status code. My current logic of retry is:

   public <T> ResponseEntity<T> sendGetRequest(String url,
                                                Class<T> responseClazz,
                                                HttpHeaders headers) {
        ResponseEntity<T> response = null;
        int count = 0;
        int maxTries = 2;
        while(true) {
            try {
                    HttpEntity request = new HttpEntity(headers);
                    response = restTemplate.exchange(url, HttpMethod.GET, request, responseClazz);
                if(response.getStatusCode() != HttpStatus.OK) {
                    log.error("null or Error response from server for  ", url);
                }
                log.info("Response received {}", response.toString());
                return response;
            }catch (ResourceAccessException rae){
                log.warn("retry count {} {}", count, rae);
                if (++count == maxTries) throw new ServerErrorException("API timeout");
            } 
        }
    }

I have also used apache http where I use CloseableHttpClient to retry for status code 500 and 504.

I have also looks to the solution of spring-retry. Is there any other method to do this?

Swarnim Kumar
  • 335
  • 5
  • 21
  • Does this answer your question? [Retry java RestTemplate HTTP request if host offline](https://stackoverflow.com/questions/32352484/retry-java-resttemplate-http-request-if-host-offline) – crizzis Mar 15 '21 at 14:53
  • Here you will get some clarity: https://www.baeldung.com/spring-retry – Shekhar Khairnar Mar 16 '21 at 07:23

1 Answers1

0

When calling HTTP request with RestTemplate, there are 2 main cases to retry:

  • Specific response HTTP statuses. For example:
    • 503 Service Unavailable status can be retried.
    • 404 Not Found can be proceeded without a retry attempt.
  • ResourceAccessException which can represent some IO exception received without getting the HTTP server response, like SocketException: Broken pipe.

For solution based on RestTemplate/HttpClient, while it exposes options to retry based on the HTTP response, combining it with IOException handling can be tricky.

Solution based on Spring RetryTemplate

@Bean(name = "restTemplateRetryTemplate")
public RetryTemplate restTemplateRetryTemplate() {
    return createRestTemplateRetryTemplate();
}

private RetryTemplate createRestTemplateRetryTemplate(boolean retryOnServerErrors) {
    Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>();
    retryableExceptions.put(ResourceAccessException.class, true);
    retryableExceptions.put(HttpServerErrorException.ServiceUnavailable.class, true);
    retryableExceptions.put(HttpServerErrorException.BadGateway.class, true);
    retryableExceptions.put(HttpServerErrorException.GatewayTimeout.class, true);
    retryableExceptions.put(HttpClientErrorException.TooManyRequests.class, true);
    return createRetryTemplate(retryableExceptions);
}

private RetryTemplate createRetryTemplate(Map<Class<? extends Throwable>, Boolean> retryableExceptions) {
    RetryTemplate retryTemplate = new RetryTemplate();

    ExponentialRandomBackOffPolicy exponentialRandomBackOffPolicy = new ExponentialRandomBackOffPolicy();
    exponentialRandomBackOffPolicy.setInitialInterval(INITIAL_INTERVAL);
    exponentialRandomBackOffPolicy.setMaxInterval(MAX_INTERVAL);
    exponentialRandomBackOffPolicy.setMultiplier(MULTIPLIER);
    retryTemplate.setBackOffPolicy(exponentialRandomBackOffPolicy);
    retryTemplate.setRetryPolicy(new SimpleRetryPolicy(MAX_ATTEMPTS, retryableExceptions));

    // Optional, for additional logging on failures.
    retryTemplate.registerListener(retryTemplateLogListener);

    return retryTemplate;
}

Usage example

@Autowired
@Qualifier("restTemplateRetryTemplate")
private RetryTemplate retryTemplate;

...

String result = retryTemplate.execute(arg -> {
    return longRestTemplate.getForObject(url, String.class);
});
Liran
  • 144
  • 2
  • 6