Hystrix/Feign 仅对 HTTP 状态 429 做出反应

Hystrix/Feign to solely react on HTTP status 429

我正在使用 spring-cloud-starter-feign 中的 Feign 将请求发送到定义的后端。我想将 Hystrix 用作断路器,但仅适用于一种类型的用例:如果后端响应 HTTP 429: Too many requests 代码,我的 Feign 客户端应该等待整整一个小时,直到它联系再次真正的后端。在此之前,应该执行回退方法。

我必须如何配置我的 Spring Boot (1.5.10) 应用程序才能完成此操作?我看到许多配置可能性,但只有几个例子——在我看来——不幸的是没有围绕用例解决。

这可以通过定义 ErrorDecoder 并手动控制 Hystrix 断路器来实现。您可以检查异常的响应代码并提供您自己的后备。此外,如果您希望重试请求,请将异常包装并抛出到 RetryException 中。

为了满足您的重试要求,还需要使用适当的配置注册一个 Retryer bean。请记住,使用 Retryer 会在持续时间内占用一个线程。 Retryer 的默认实现也使用指数退避策略。

这是从 OpenFeign 文档中获取的 ErrorDecoder 示例:

public class StashErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() >= 400 && response.status() <= 499) {
            return new StashClientException(
                response.status(),
                response.reason()
            );
        }
        if (response.status() >= 500 && response.status() <= 599) {
            return new StashServerException(
                response.status(),
                response.reason()
            );
        }
        return errorStatus(methodKey, response);
    } 
}

在你的情况下,你会根据需要对 419 做出反应。

你可以在运行时强行打开断路器设置属性

hystrix.command.HystrixCommandKey.circuitBreaker.forceOpen

ConfigurationManager.getConfigInstance()
    .setProperty(
    "hystrix.command.HystrixCommandKey.circuitBreaker.forceOpen", true);

用你自己的命令替换HystrixCommandKey。您需要在所需时间后将此断路器恢复为闭合状态。

我可以通过以下调整解决它:

application.yml 中的属性:

hystrix.command.commandKey:
  execution.isolation.thread.timeoutInMilliseconds: 10_000
  metrics.rollingStats.timeInMilliseconds: 10_000
  circuitBreaker:
    errorThresholdPercentage: 1
    requestVolumeThreshold: 1
    sleepWindowInMilliseconds: 3_600_000

各自的代码 Java class:

@HystrixCommand(fallbackMethod = "fallbackMethod", commandKey = COMMAND_KEY)
public void doCall(String parameter) {
    try {
        feignClient.doCall(parameter);
    } catch (FeignException e) {
        if (e.status() == 429) {
            throw new TooManyRequestsException(e.getMessage());
        } 
    }
}