Ribbon Sets url Level Timeout

  springcloud

Order

The timeout setting of ribbon can only be divided according to the forwarded serviceId, and cannot be directly set in each forwarded link like nginx. Hack here to implement the basic ribbon timeout setting for url. The specific idea is to rewrite the toRequest method of RibbonApacheHttpRequest and then set it up.

CustomRibbonApacheHttpRequest

public class CustomRibbonApacheHttpRequest extends RibbonApacheHttpRequest {
    public CustomRibbonApacheHttpRequest(RibbonCommandContext context) {
        super(context);
    }

    @Override
    public HttpUriRequest toRequest(RequestConfig requestConfig) {
        final RequestBuilder builder = RequestBuilder.create(this.context.getMethod());
        builder.setUri(this.uri);
        for (final String name : this.context.getHeaders().keySet()) {
            final List<String> values = this.context.getHeaders().get(name);
            for (final String value : values) {
                builder.addHeader(name, value);
            }
        }

        for (final String name : this.context.getParams().keySet()) {
            final List<String> values = this.context.getParams().get(name);
            for (final String value : values) {
                builder.addParameter(name, value);
            }
        }

        if (this.context.getRequestEntity() != null) {
            final BasicHttpEntity entity;
            entity = new BasicHttpEntity();
            entity.setContent(this.context.getRequestEntity());
            // if the entity contentLength isn't set, transfer-encoding will be set
            // to chunked in org.apache.http.protocol.RequestContent. See gh-1042
            if (this.context.getContentLength() != null) {
                entity.setContentLength(this.context.getContentLength());
            } else if ("GET".equals(this.context.getMethod())) {
                entity.setContentLength(0);
            }
            builder.setEntity(entity);
        }

        customize(this.context.getRequestCustomizers(), builder);

        //todo 这里处理个性的timeout信息
        if(uri.getPath().equals("/review/timeout")){
            RequestConfig.Builder configBuilder = RequestConfig.copy(builder.getConfig());
            configBuilder.setConnectionRequestTimeout(30*1000);
            configBuilder.setConnectTimeout(30*1000);
            configBuilder.setSocketTimeout(30*1000);
            builder.setConfig(configBuilder.build());
        }else{
            builder.setConfig(requestConfig);
        }

        return builder.build();
    }
}

CustomHttpClientRibbonCommand

public class CustomHttpClientRibbonCommand extends HttpClientRibbonCommand {

    public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties) {
        super(commandKey, client, context, zuulProperties);
    }

    public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties, ZuulFallbackProvider zuulFallbackProvider) {
        super(commandKey, client, context, zuulProperties, zuulFallbackProvider);
    }

    @Override
    protected RibbonApacheHttpRequest createRequest() throws Exception {
        RibbonApacheHttpRequest ribbonApacheHttpRequest = new CustomRibbonApacheHttpRequest(this.context);
        return ribbonApacheHttpRequest;
    }
}

CustomHttpClientRibbonCommandFactory

public class CustomHttpClientRibbonCommandFactory extends HttpClientRibbonCommandFactory{

    private final SpringClientFactory clientFactory;

    private final ZuulProperties zuulProperties;

    public CustomHttpClientRibbonCommandFactory(SpringClientFactory clientFactory, ZuulProperties zuulProperties) {
        super(clientFactory, zuulProperties);
        this.clientFactory = clientFactory;
        this.zuulProperties = zuulProperties;
    }

    public CustomHttpClientRibbonCommandFactory(SpringClientFactory clientFactory, ZuulProperties zuulProperties, Set<ZuulFallbackProvider> fallbackProviders) {
        super(clientFactory, zuulProperties, fallbackProviders);
        this.clientFactory = clientFactory;
        this.zuulProperties = zuulProperties;
    }

    @Override
    public HttpClientRibbonCommand create(RibbonCommandContext context) {
        ZuulFallbackProvider zuulFallbackProvider = getFallbackProvider(context.getServiceId());
        final String serviceId = context.getServiceId();
        final RibbonLoadBalancingHttpClient client = this.clientFactory.getClient(
                serviceId, RibbonLoadBalancingHttpClient.class);
        client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId));

        return new CustomHttpClientRibbonCommand(serviceId, client, context, zuulProperties, zuulFallbackProvider);
    }
}

Configuration

@Autowired(required = false)
    private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet();

    @Bean
    @ConditionalOnMissingBean
    public RibbonCommandFactory<?> ribbonCommandFactory(
            SpringClientFactory clientFactory, ZuulProperties zuulProperties) {
        return new CustomHttpClientRibbonCommandFactory(clientFactory, zuulProperties, zuulFallbackProviders);
    }

Timeout level of gateway

zuul

zuul:
  max:
    host:
      connections: 500
  host:
    socket-timeout-millis: 60000
    connect-timeout-millis: 60000

ribbon

ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1
  eureka:
    enabled: true

hystrix

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000

Summary

If you go to the gateway, there will be a three-tier timeout, one for zuul, one for ribbon and one for hystrix. For the timeout setting of hystrix, the class AbstractRibbonCommand does not expose the Setter method for setting hystrix, so it cannot be extended by inheritance. Therefore, if you want to customize the ribbon timeout, you need the timeout to be less than hystrix, otherwise it will be overtime by hystrix in advance, which will not be effective.