com.netflix.hystrix.exception.HystrixRuntimeException: XxxClient#getXxx() failed and fallback failed

7 篇文章 0 订阅

异常:

│ com.netflix.hystrix.exception.HystrixRuntimeException: XxxClient#getXxx() failed and fallback failed.                                                                                  
│     at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:832)                                                                                                                              
│     at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:807)                                                                                                                              
│     at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:140)                                                                                
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at com.netflix.hystrix.AbstractCommand$DeprecatedOnFallbackHookApplication$1.onError(AbstractCommand.java:1472)                                                                                       
│     at com.netflix.hystrix.AbstractCommand$FallbackHookApplication$1.onError(AbstractCommand.java:1397)                                                                                                   
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at rx.observers.Subscribers$5.onError(Subscribers.java:230)                                                                                                                                           
│     at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44)                                                                                                                              
│     at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28)                                                                                                                              
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)                                                                                                                              
│     at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)                                                                                                                              
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)                                                                                                                        
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)                                                                                                                        
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)                                                                                                                                
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)                                                                                                                                
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)                                                                                                                                
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)                                                                                                                                
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)                                                                                                                        
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)                                                                                                                        
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)                                                                                                                        
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)                                                                                                                        
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)                                                                                                                                
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)                                                                                                                                
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)                                                                                                                        
│     at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)                                                                                                                        
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)                                                                                                                                
│     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)                                                                                                                                
│     at rx.Observable.unsafeSubscribe(Observable.java:10327)                                                                                                                                               
│     at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:142)                                                                                
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$3.onError(AbstractCommand.java:1194)                                                                                          
│     at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.onError(OperatorSubscribeOn.java:80)                                                                                               
│     at rx.observers.Subscribers$5.onError(Subscribers.java:230)                                                                                                                                           
│     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87)                                                                                                  
│     at rx.observers.Subscribers$5.onError(Subscribers.java:230)                                                                                                                                           
│     at com.netflix.hystrix.AbstractCommand$DeprecatedOnRunHookApplication$1.onError(AbstractCommand.java:1431)                                                                                            
│     at com.netflix.hystrix.AbstractCommand$ExecutionHookApplication$1.onError(AbstractCommand.java:1362)     

问题产生:

通过spring openfeign的FallbackFactory对feign接口进行降级熔断操作;具体问题产生原因是FallbackFactory#create创建的对象,通过反射调用相关方法时,方法内部抛出了 Runtime Exception,也就是说并非降级操作不起作用,而是写的降级方法本身存在问题!比如 方法內抛出了异常、属性注入失败等等

OpenFeign提供的两种降级操作:

1、fallback

@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
    protected interface TestClient {

        @RequestMapping(method = RequestMethod.GET, value = "/hello")
        Hello getHello();

        @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
        String getException();

    }

    @Component
    static class Fallback implements TestClient {

        @Override
        public Hello getHello() {
            throw new NoFallbackAvailableException("Boom!", new RuntimeException());
        }

        @Override
        public String getException() {
            return "Fixed response";
        }

    }

这种方式最简单,当feign接口调用失败时直接走fallback方法,不足之处在于拿不到具体feign调用失败的err信息

2、fallbackFactory

@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
            fallbackFactory = TestFallbackFactory.class)
    protected interface TestClientWithFactory {

        @RequestMapping(method = RequestMethod.GET, value = "/hello")
        Hello getHello();

        @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
        String getException();

    }

    @Component
    static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {

        @Override
        public FallbackWithFactory create(Throwable cause) {
            return new FallbackWithFactory();
        }

    }

    static class FallbackWithFactory implements TestClientWithFactory {

        @Override
        public Hello getHello() {
            throw new NoFallbackAvailableException("Boom!", new RuntimeException());
        }

        @Override
        public String getException() {
            return "Fixed response";
        }
}

通过这种方式就可以在创建fallback实体对象的时候把throwable错误信息传回来

3、fallback与fallbackFactory的差别:
两者最终的处理方式都是一致的,fallbackFactory在真正使用的时候才创建需要的fallback对象,这个时候就很方便的将throwable信息传回;fallback最终也会使用默认的工厂方法:

  /** Returns a constant fallback after logging the cause to FINE level. */
  final class Default<T> implements FallbackFactory<T> {
    // jul to not add a dependency
    final Logger logger;
    final T constant;

    public Default(T constant) {
      this(constant, Logger.getLogger(Default.class.getName()));
    }

    Default(T constant, Logger logger) {
      this.constant = checkNotNull(constant, "fallback");
      this.logger = checkNotNull(logger, "logger");
    }

    @Override
    public T create(Throwable cause) {
      if (logger.isLoggable(Level.FINE)) {
        logger.log(Level.FINE, "fallback due to: " + cause.getMessage(), cause);
      }
      return constant;
    }

    @Override
    public String toString() {
      return constant.toString();
    }
  }

当然这个默认的工厂方法创建的fallback对象是没有携带throwable信息的

来看看两者最终都会调用fallback的方法:
feign.hystrix.HystrixInvocationHandler#invoke

  public Object invoke(final Object proxy, final Method method, final Object[] args)
      throws Throwable {

 .......

    HystrixCommand<Object> hystrixCommand =
        new HystrixCommand<Object>(setterMethodMap.get(method)) {
      .......

          @Override
          protected Object getFallback() {
            if (fallbackFactory == null) {
              return super.getFallback();
            }
            try {
            // 如果要走fallback的话,最终都就走到这里来
            // fallbackFactory要么是默认的,要么是自定义的,也就是对应的以上两种定义fallback的方式
              Object fallback = fallbackFactory.create(getExecutionException());
              Object result = fallbackMethodMap.get(method).invoke(fallback, args);
              if (isReturnsHystrixCommand(method)) {
                return ((HystrixCommand) result).execute();
              } else if (isReturnsObservable(method)) {
                // Create a cold Observable
                return ((Observable) result).toBlocking().first();
              } else if (isReturnsSingle(method)) {
                // Create a cold Observable as a Single
                return ((Single) result).toObservable().toBlocking().first();
              } else if (isReturnsCompletable(method)) {
                ((Completable) result).await();
                return null;
              } else if (isReturnsCompletableFuture(method)) {
                return ((Future) result).get();
              } else {
                return result;
              }
            } catch (IllegalAccessException e) {
              // shouldn't happen as method is public due to being an interface
              throw new AssertionError(e);
            } catch (InvocationTargetException | ExecutionException e) {
              // Exceptions on fallback are tossed by Hystrix
              throw new AssertionError(e.getCause());
            } catch (InterruptedException e) {
              // Exceptions on fallback are tossed by Hystrix
              Thread.currentThread().interrupt();
              throw new AssertionError(e.getCause());
            }
          }
        };

........




简单来说: 两种降级操作 fallback 和 fallbackFactory的处理方式是一致的,如果想要拿到具体的异常信息就使用 fallbackFactory


调试版本: org.springframework.cloud:spring-cloud-openfeign:2.2.5.RELEASE 以及其依赖的io.github.openfeign:feign-hystrix:10.10.1




以上是个人理解,如有问题请指出!

参考 spring-cloud-openfeign

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柏油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值