javaspringspring-retry

Exclude read time out from @Retryable annotation


I have a retryable REST call which retries on specific cases. Currently, it retries even on read timeout & connection timeout scenario as well.

@Retryable(value = {RestClientException.class},maxAttempts = 2,
        exclude = {HttpClientErrorException.BadRequest.class})
public ResponseEntity<String> testMethod() throws Exception {
    return restTemplateRtp.exchange("http://localhost:8080/api/test", HttpMethod.POST, request, String.class);
}

In case of a readtimeout, the retry retries for 2 times, and then fails with this exception:

org.springframework.web.client.ResourceAccessException: I/O error 
on POST request for "http://localhost:8080/api/test": Read timed 
out; nested exception is java.net.SocketTimeoutException: Read timed out

I dont want to retry on read timeout but want the retry to continue for connect timeout. When I try to add SocketTimeoutException in the exclude, its still retrying for read timeout as well.

How to handle this scenario? I cant add ResourceAccessException to the exclude, then both the read & connect timeouts will stop getting retried.


Solution

  • From the exception stack trace i can say the ResourceAccessException is top level exception that is thrown due to underlying java.net.SocketTimeoutException.

    and, from the java-docs socket timeout will be thrown on multiple use cases

    Signals that a timeout has occurred on a socket read or accept.

    If would suggest adding custom logic for excluding any underlying exceptions

    @Retryable(value = {RestClientException.class},maxAttempts = 2,
        exclude = {HttpClientErrorException.BadRequest.class})
    public ResponseEntity<String> testMethod() throws Exception {
    
    try {
         return restTemplateRtp.exchange("http://localhost:8080/api/test", HttpMethod.POST, request, String.class);
    
        }catch(ResourceAccessException ex) {
    
          if(ex.getCause() instanceOf java.net.SocketTimeoutException 
               && ex.getCause().getMessage().equals("Read timed out")) {
                //exclude don't retry and return something
             }
             // else throw ex;
    
         }
        
       }
    }