Open wentfar opened 2 years ago
当被调用逻辑抛出异常...
是业务异常吗,还是限流异常(BlockException
)
如果是业务异常,会根据异常类型是否是SofaRpcException
直接抛出,或者包装为SofaRpcException
向上抛
处理逻辑在AbstractSofaRpcFilter#traceOtherException
方法里
如果是限流异常,默认会使用DefaultSofaRpcFallback
,里面抛出SentinelRpcException
,
可通过SofaRpcFallbackRegistry#setProviderFallback
指定自定义的限流fallback处理逻辑
如果是业务异常,会根据异常类型是否是
SofaRpcException
直接抛出,或者包装为SofaRpcException
向上抛 处理逻辑在AbstractSofaRpcFilter#traceOtherException
方法里
是业务异常,我这边调试下来调用链大概如下:FilterChain->ProviderExceptionFilter->FilterInvoker->RpcServiceContextFilter->FilterInvoker->ProviderBaggageFilter->。。。->SentinelSofaRpcProviderFilter->。。。->ProviderInvoker
业务异常会在ProviderInvoker中被catch住,然后转换成正常响应,依次经过各个filter,最终返回到SentinelSofaRpcProviderFilter,不能进入AbstractSofaRpcFilter#traceOtherException。
难道我有啥特殊配置?
是的,你描述的调用链没问题,SentinelSofaRpcProviderFilter
类上面注解里配置了order = -1000
,会在SofaRPC所有系统的Filter之后,ProviderInvoker
之前执行。
如果是Service接口实现里的业务异常,会在ProviderInvoker
反射调用catch住InvocationTargetException
,
抱歉。。我前面描述是错的,由于ProviderInvoker
对业务异常有处理不会向上抛,确实不会进AbstractSofaRpcFilter#traceOtherException
。
业务异常从语义讲跟Sentinel限流是无关的,项目中自行处理或者根据框架提供的扩展统一处理业务异常即可。
比如在consumer端,可以捕获到provider端抛的业务异常。
(例:在sentinel-demo-sofa-rpc
里运行DemoProvider
和DemoConsumer
,修改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,可参考上面业务异常的处理思路。
感谢,感谢,回答很专业,我再吸收理解一下。
(例:在
sentinel-demo-sofa-rpc
里运行DemoProvider
和DemoConsumer
,修改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。
你好,我这边使用了SofaRpc,目前正在集成sentinel,目前使用了sentinel-sofa-rpc-adapter进行集成,调试发现程序执行到了SentinelSofaRpcProviderFilter,但是当被调用逻辑抛出异常时,被调用方接收到了异常信息,但是却没有异常的回调。
我的问题是,如何使用sentinel-sofa-rpc-adapter集成sentinel,并且能够在provider抛出InvocationTargetException时,进入到自定义的fallback函数中去。
环境: windows10,sofastack,sentinel
@sczyh30 @cdfive