Feign client retry on exception

NoobEditor picture NoobEditor · Jul 11, 2019 · Viewed 9.5k times · Source

So far we have a feign client which in case of exception, we used to retry as below

Retryer<ClientResponse> retryer = RetryerBuilder.<ClientResponse>newBuilder()
  .retryIfExceptionOfType(FeignException.class)
  .withStopStrategy(StopStrategies.stopAfterAttempt(retryCount))
  .withWaitStrategy(WaitStrategies.exponentialWait(maxWaitSeconds, TimeUnit.SECONDS))
  .build();
    
retryer.call(() -> { 
  return client.doStuffs(someInput); }
);

recently I tried moving from this custom retryer to an inbuilt feign retryer as below :

Feign client = Feign.builder()
    .decoder(jacksonDecoder)
    .encoder(jacksonEncoder)
    .logger(slf4jLogger)
    .client(okHttpClient)
    .retryer(new Retryer.Default(
                            SECONDS.toMillis(minWaitSeconds), 
                            SECONDS.toMillis(maxWaitSeconds), 
                            retryCount
            ))
    .requestInterceptor(new BasicAuthRequestInterceptor(clientConfig.getUser(), clientConfig.getPassword()))
    .target(target);
    
client.doStuffs(someInput);

understanding was that feign client itself would be taking care of exception but apparently, that's not the case, the minute client throws a 5xx, I get an exception with no retries. Is there something else needed for the implementation to retry?

this service is in dropwizard, git and SO threads are mostly around spring / ribbon which is not the case with me.

dep

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-core</artifactId>
    <version>${feign.version}</version>
</dependency>

Answer

Kevin Davis picture Kevin Davis · Jul 18, 2019

Without additional configuration, Feign will retry on IOExceptions only. If you wish to retry based on status codes, you will need to create an ErrorDecoder that throws a RetryableException or derivative of, in order to trigger a retry.

Here is simple example:

class MyErrorDecoder implements ErrorDecoder {
    public Exception decode(String methodKey, Response response) {
        if (response.status() == 503) {
            throw new RetryableException(
                response.status(), 
                "Service Unavailable", 
                response.request().httpMethod(), 
                null);
        } else {
            return new RuntimeException("error");
        }
    }
}

For more examples, take a look at the Error Handling documentation.