【问题标题】:Feign: Retry depending on response statusFeign:根据响应状态重试
【发布时间】:2016-10-03 12:13:58
【问题描述】:

我目前正在使用 Spring Cloud 和 Feign 在我的应用程序中使用微服务。由于它可能发生,数据库连接等在单个服务实例中失败,使其返回 500 HTTP 状态代码,我想确保下一个服务器由服务的客户端重试。目前,Ribbon 的重试机制在服务根本没有运行时就像一个魅力,但是当它收到 500 状态码时仍然会立即返回错误,而无需任何重试。

如果实例返回 500 响应,是否可以配置 Feign 客户端或其底层 Ribbon 负载均衡器以重试下一个服务器?

配置与此线程中的配置几乎相同:Does Feign retry require some sort of configuration?

我很想使用像 Ribbons 的 HttpResponseValidator (https://github.com/Netflix/ribbon/blob/master/ribbon/src/main/java/com/netflix/ribbon/http/HttpResponseValidator.java) 这样的实现,但我找不到任何可用于 Spring Cloud 及其 Feign/Ribbon 集成的东西

【问题讨论】:

    标签: java spring spring-cloud netflix-feign spring-cloud-netflix


    【解决方案1】:

    这个问题很老了,可能已经找到了解决方案,或者当时不可能。无论如何,我认为这个答案可能仍然对某人有帮助 8 )。 请将此作为参考,此代码不用于生产用途。 Feign 允许你配置 errorDecoder - 这就是魔法发生的地方。

    Feign.Builder builder = Feign.builder()
      .errorDecoder(new RetryOnScaleErrorDecoder())
    

    这是实现,我使用该类在服务扩展时从 AWS 收到的 HTTP 错误 429 上重试请求

    public static class RetryOnScaleErrorDecoder implements ErrorDecoder {
    
      @Override
      public Exception decode(String methodKey, Response response) {
        FeignException exception = errorStatus(methodKey, response);
        // This is a terrible part please check how feign.codec.ErrorDecoder.RetryAfterDecoder is implemented for proper parsing of retry-after header
        Collection<String> headers = response.headers().get("Retry-After");
    
        String repeatAfterString = "0";
        if (Objects.nonNull(headers)) {
          repeatAfterString = Iterables.getFirst(headers, "0");
        }
    
        assert repeatAfterString != null;
    
        Date repeatAfter = new Date(currentTimeMillis());
    
        if (repeatAfterString.matches("^[0-9]+$")) {
          try {
            long deltaMillis = SECONDS.toMillis(Long.parseLong(repeatAfterString));
            repeatAfter = new Date(currentTimeMillis() + deltaMillis);
          } catch (NumberFormatException ignored) {
            // TODO: logging
          }
        }
        // That's the part where we decide to retry based on status code value
        if (exception.status() == 429) {
          return new RetryableException(
              response.status(),
              exception.getMessage(),
              response.request().httpMethod(),
              exception,
              repeatAfter
          );
        }
        return exception;
      }
    }
    

    我认为与 Ribbon 结合使用会产生预期的效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-26
      • 2020-12-10
      • 2019-09-19
      • 2019-06-15
      • 1970-01-01
      • 2020-03-02
      • 2020-01-21
      • 2021-07-07
      相关资源
      最近更新 更多