假设:根据回复状态重试

时间:2016-06-03 12:17:31

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

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

如果实例返回500响应,是否可以将Feign客户端或其基础功能区负载均衡器配置为重试下一个服务器?

配置与此主题中的配置几乎相同: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集成的任何东西

2 个答案:

答案 0 :(得分:0)

这个问题很老,解决方案可能已经找到或当时无法解决。无论如何,我认为答案仍然可以帮助某人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结合使用将产生预期的结果。

答案 1 :(得分:-2)

来自Josh Lang的GitHub LiveLessons存储库可以帮助您弄清楚如何解决它,看看https://github.com/livelessons-spring/building-microservices/tree/master/livelessons-choreography