Search code examples
javaspringload-balancingspring-cloud-netflixnetflix-ribbon

Automatic retries with Ribbon (without zuul): not working + wrong documentation?


In the latest versions of spring cloud Netflix's official documentation (for example 2.0.2.RELEASE, the last GA version) it states:

When Spring Retry is present, load-balanced RestTemplates, Feign, and Zuul automatically retry any failed requests (assuming your configuration allows doing so).

But that seems wrong concerning the use of standalone Ribbon (i.e. load-balanced RestTemplates). I couldn't make it work nor found any working example. Moreover, I found other sources stating quite the opposite was true, such as:

So, it's the documentation wrong or is the whole world missing something?


Solution

  • We found the same issue; Zuul will neither retry nor failover to alternative servers in the ribbon server list using the default (Apache Http Client) configuration. We tracked it down to this line of code in the RibbonLoadBalancingHttpClient class:

    @Override
    public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
            RibbonApacheHttpRequest request, IClientConfig requestConfig) {
        return new RequestSpecificRetryHandler(false, false, RetryHandler.DEFAULT,
                requestConfig);
    }
    

    The hardcoded false, false parameters effectively disable retry from ever happening. It is easy to fix this.

    Add this to your Zuul main application class:

    @RibbonClients(
        defaultConfiguration = {EurekaRibbonClientConfiguration.class,
            MyRibbonConfiguration.class})
    

    Create a class, MyRibbonConfiguration and use it to emulate the ribbonLoadBalancingHttpClient method here except we override and fix the getRequestSpecificRetryHandler method that's causing problems.

    public class MyRibbonConfiguration {
    
      @RibbonClientName
      private String name = "client";
    
      @Bean
      public RibbonLoadBalancingHttpClient ribbonLoadBalancingHttpClient(
          IClientConfig config, ServerIntrospector serverIntrospector,
          ILoadBalancer loadBalancer, RetryHandler retryHandler, CloseableHttpClient httpClient) {
    
        RibbonLoadBalancingHttpClient client =
            new RibbonLoadBalancingHttpClient(httpClient, config, serverIntrospector) {
              @Override
              public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
                  RibbonApacheHttpRequest request, IClientConfig requestConfig) {
                return new RequestSpecificRetryHandler(true, true, RetryHandler.DEFAULT,
                    requestConfig);
              }
            };
    
        client.setLoadBalancer(loadBalancer);
        client.setRetryHandler(retryHandler);
    
        Monitors.registerObject("Client_" + this.name, client);
        return client;
      }
    }
    

    Adjust true, true to reference from properties if you want. With this in place Zuul will start respecting the ribbon.MaxAutoRetries and ribbon.MaxAutoRetriesNextServer properties.

    Note that if you are using Ribbon with Feign for server->server calls then those Feign calls are not affected because OpenFeign hardcodes those two parameters to true, true.