Sentinel 使用sentinel-sofa-rpc-adapter,在被调用方抛出InvocationTargetException时,如何使用自定义falback接收,

bq8i3lrv  于 2022-10-19  发布在  其他
关注(0)|答案(5)|浏览(256)

你好,我这边使用了SofaRpc,目前正在集成sentinel,目前使用了sentinel-sofa-rpc-adapter进行集成,调试发现程序执行到了SentinelSofaRpcProviderFilter,但是当被调用逻辑抛出异常时,被调用方接收到了异常信息,但是却没有异常的回调。

我的问题是,如何使用sentinel-sofa-rpc-adapter集成sentinel,并且能够在provider抛出InvocationTargetException时,进入到自定义的fallback函数中去。

环境:
windows10,sofastack,sentinel

@sczyh30@cdfive

vaqhlq81

vaqhlq811#

当被调用逻辑抛出异常...

是业务异常吗,还是限流异常( BlockException

如果是业务异常,会根据异常类型是否是 SofaRpcException 直接抛出,或者 Package 为 SofaRpcException 向上抛
处理逻辑在 AbstractSofaRpcFilter#traceOtherException 方法里

如果是限流异常,默认会使用 DefaultSofaRpcFallback ,里面抛出 SentinelRpcException
可通过 SofaRpcFallbackRegistry#setProviderFallback 指定自定义的限流fallback处理逻辑

2wnc66cl

2wnc66cl2#

如果是业务异常,会根据异常类型是否是 SofaRpcException 直接抛出,或者 Package 为 SofaRpcException 向上抛
处理逻辑在 AbstractSofaRpcFilter#traceOtherException 方法里

是业务异常,我这边调试下来调用链大概如下:FilterChain->ProviderExceptionFilter->FilterInvoker->RpcServiceContextFilter->FilterInvoker->ProviderBaggageFilter->。。。->SentinelSofaRpcProviderFilter->。。。->ProviderInvoker

业务异常会在ProviderInvoker中被catch住,然后转换成正常响应,依次经过各个filter,最终返回到SentinelSofaRpcProviderFilter,不能进入AbstractSofaRpcFilter#traceOtherException。

难道我有啥特殊配置?

2g32fytz

2g32fytz3#

是的,你描述的调用链没问题, SentinelSofaRpcProviderFilter 类上面注解里配置了 order = -1000 ,会在SofaRPC所有系统的Filter之后, ProviderInvoker 之前执行。
如果是Service接口实现里的业务异常,会在 ProviderInvoker 反射调用catch住 InvocationTargetException
抱歉。。我前面描述是错的,由于 ProviderInvoker 对业务异常有处理不会向上抛,确实不会进 AbstractSofaRpcFilter#traceOtherException

业务异常从语义讲跟Sentinel限流是无关的,项目中自行处理或者根据框架提供的扩展统一处理业务异常即可。
比如在consumer端,可以捕获到provider端抛的业务异常。
(例:在 sentinel-demo-sofa-rpc 里运行 DemoProviderDemoConsumer ,修改 DemoServiceImpl#sayHello ,里面抛一个业务异常)

或考虑在项目Provider端单独实现一个SofaRPC的Filter,里面判断 SofaResponse 是否有业务异常来实现项目的统一异常处理。
(判断可参考 AbstractSofaRpcFilter#traceResponseException )
我的问题是,如何使用sentinel-sofa-rpc-adapter集成sentinel,并且能够在provider抛出InvocationTargetException时,进入到自定义的fallback函数中去。

这里自定义的fallback(实现 SofaRpcFallback 接口),它主要是用于处理限流异常(Sentinel的 BlockException
即当系统或者接口发生限流时的fallback处理,而不是业务异常的fallback处理。

因此实现是发生限流异常时才会进限流fallback中去,
Sentinel对其它框架适配也是如此哈(如sentienl-dubbo-adapter、sentinel-spring-webmvc-adapter等)

如果要实现业务异常进入到自定义的fallback,可参考上面业务异常的处理思路。

yvgpqqbh

yvgpqqbh4#

感谢,感谢,回答很专业,我再吸收理解一下。

lkaoscv7

lkaoscv75#

(例:在 sentinel-demo-sofa-rpc 里运行 DemoProviderDemoConsumer ,修改 DemoServiceImpl#sayHello ,里面抛一个业务异常)

我又真正触发了BlockException,在SentinelSofaRpcProviderFilter中的确进入了DefaultSofaRpcFallback,但是最终到/com/alipay/sofa/rpc/server/bolt/BoltServerProcessor.java:182,该行:MessageBuilder.buildSofaErrorResponse(e.getMessage()),如下:

// 真正调用
        response = doInvoke(serviceName, invoker, request);
         if (bizCtx.isRequestTimeout()) { // 加上丢弃超时的响应的逻辑
            throwable = clientTimeoutWhenSendResponse(appName, serviceName, bizCtx.getRemoteAddress());
            break invoke;
        }
    }
} catch (Exception e) {
    // 服务端异常,不管是啥异常
    LOGGER.errorWithApp(appName, "Server Processor Error!", e);
    throwable = e;
    response = MessageBuilder.buildSofaErrorResponse(e.getMessage());
}

// Response不为空,代表需要返回给客户端
if (response != null) {
    RpcInvokeContext invokeContext = RpcInvokeContext.peekContext();
    isAsyncChain = CommonUtils.isTrue(invokeContext != null ?
        (Boolean) invokeContext.remove(RemotingConstants.INVOKE_CTX_IS_ASYNC_CHAIN) : null);
    // 如果是服务端异步代理模式,特殊处理,因为该模式是在业务代码自主异步返回的
    if (!isAsyncChain) {
        // 其它正常请求
        try { // 这个try-catch 保证一定要记录tracer
            asyncCtx.sendResponse(response);
        } finally {
            if (EventBus.isEnable(ServerSendEvent.class)) {
                EventBus.post(new ServerSendEvent(request, response, throwable));
            }
        }
    }
}
} catch (Throwable e) {

最终在Consumer端得到SofaRpcException,而不是BlockException。

相关问题