diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/README.md b/sentinel-adapter/sentinel-apache-dubbo-adapter/README.md index f46cf41da7..9d232bef03 100755 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/README.md +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/README.md @@ -1,4 +1,4 @@ -# Sentinel Apache Dubbo Adapter +# Sentinel Apache Dubbo Adapter (for 2.7.x+) > Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/主流框架的适配#dubbo)。 @@ -21,7 +21,7 @@ To use Sentinel Dubbo Adapter, you can simply add the following dependency to yo The Sentinel filters are **enabled by default**. Once you add the dependency, the Dubbo services and methods will become protected resources in Sentinel, which can leverage Sentinel's flow control and guard ability when rules are configured. -Demos can be found in [sentinel-demo-dubbo](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-dubbo). +Demos can be found in [sentinel-demo-apache-dubbo](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-apache-dubbo). If you don't want the filters enabled, you can manually disable them. For example: @@ -37,8 +37,8 @@ For more details of Dubbo filter, see [here](http://dubbo.apache.org/en-us/docs/ The resource for Dubbo services has two granularities: service interface and service method. -- Service interface:resourceName format is `interfaceName`,e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService` -- Service method:resourceName format is `interfaceName:methodSignature`,e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)` +- Service interface: resourceName format is `interfaceName`, e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService` +- Service method: resourceName format is `interfaceName:methodSignature`, e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)` ## Flow control based on caller diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java index 323fa12266..8d4009f23a 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java @@ -21,11 +21,10 @@ import org.apache.dubbo.rpc.Invoker; /** - * Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}. + * Base class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}. * * @author Zechao Zheng */ - public abstract class BaseSentinelDubboFilter implements Filter { diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java index 41f3acb67c..02b8c5ad91 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java @@ -19,11 +19,13 @@ import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig; import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.slots.block.BlockException; + import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.*; import org.apache.dubbo.rpc.support.RpcUtils; import java.util.LinkedList; +import java.util.Optional; import java.util.function.BiConsumer; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; @@ -38,6 +40,7 @@ * * @author Carpenter Lee * @author Eric Zhao + * @author Lin Liang */ @Activate(group = CONSUMER) public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter { @@ -64,7 +67,6 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept } else { return asyncInvoke(invoker, invocation); } - } private Result syncInvoke(Invoker invoker, Invocation invocation) { @@ -75,7 +77,8 @@ private Result syncInvoke(Invoker invoker, Invocation invocation) { String methodResourceName = getMethodName(invoker, invocation, prefix); try { interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT); - methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments()); + methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, + invocation.getArguments()); Result result = invoker.invoke(invocation); if (result.hasException()) { Tracer.traceEntry(result.getException(), interfaceEntry); @@ -98,24 +101,27 @@ private Result syncInvoke(Invoker invoker, Invocation invocation) { } } - private Result asyncInvoke(Invoker invoker, Invocation invocation) { LinkedList queue = new LinkedList<>(); String prefix = DubboAdapterGlobalConfig.getDubboConsumerResNamePrefixKey(); String interfaceResourceName = getInterfaceName(invoker, prefix); String methodResourceName = getMethodName(invoker, invocation, prefix); try { - queue.push(new EntryHolder(SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT), null)); - queue.push(new EntryHolder(SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments()), invocation.getArguments())); + queue.push(new EntryHolder( + SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT), null)); + queue.push(new EntryHolder( + SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, + EntryType.OUT, 1, invocation.getArguments()), invocation.getArguments())); Result result = invoker.invoke(invocation); - result.whenCompleteWithContext(new BiConsumer() { - @Override - public void accept(Result result, Throwable throwable) { - while (!queue.isEmpty()) { - EntryHolder holder = queue.pop(); - Tracer.traceEntry(result.getException(), holder.entry); - exitEntry(holder); - } + result.whenCompleteWithContext((r, throwable) -> { + Throwable error = throwable; + if (error == null) { + error = Optional.ofNullable(r).map(Result::getException).orElse(null); + } + while (!queue.isEmpty()) { + EntryHolder holder = queue.pop(); + Tracer.traceEntry(error, holder.entry); + exitEntry(holder); } }); return result; @@ -127,10 +133,9 @@ public void accept(Result result, Throwable throwable) { } } - class EntryHolder { + static class EntryHolder { final private Entry entry; - final private Object[] params; public EntryHolder(Entry entry, Object[] params) { diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java index b8dc5fd6a9..867073e147 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java @@ -20,6 +20,7 @@ import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.slots.block.BlockException; + import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -74,7 +75,8 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept // at entrance of invocation chain only (for inbound traffic). ContextUtil.enter(methodResourceName, origin); interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN); - methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments()); + methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, + invocation.getArguments()); Result result = invoker.invoke(invocation); if (result.hasException()) { Tracer.traceEntry(result.getException(), interfaceEntry); @@ -98,6 +100,5 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept } } - } diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java index b9cf9489a9..43664f0a38 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java @@ -43,13 +43,11 @@ public final class DubboAdapterGlobalConfig { private static final String DEFAULT_DUBBO_CONSUMER_PREFIX = "dubbo:consumer:"; public static final String DUBBO_INTERFACE_GROUP_VERSION_ENABLED = "csp.sentinel.dubbo.interface.group.version.enabled"; - public static final String TRACE_BIZ_EXCEPTION_ENABLED = "csp.sentinel.dubbo.trace.biz.exception.enabled"; private static volatile DubboFallback consumerFallback = new DefaultDubboFallback(); private static volatile DubboFallback providerFallback = new DefaultDubboFallback(); private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser(); - public static boolean isUsePrefix() { return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY)); } @@ -74,16 +72,6 @@ public static Boolean getDubboInterfaceGroupAndVersionEnabled() { return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED)); } - public static Boolean getDubboBizExceptionTraceEnabled() { - String traceBizExceptionEnabled = SentinelConfig.getConfig(TRACE_BIZ_EXCEPTION_ENABLED); - if (StringUtil.isNotBlank(traceBizExceptionEnabled)) { - return TRUE_STR.equalsIgnoreCase(traceBizExceptionEnabled); - } - return true; - } - - - public static DubboFallback getConsumerFallback() { return consumerFallback; } diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java index 159d1dbe60..d5099b1d6a 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java @@ -16,7 +16,7 @@ package com.alibaba.csp.sentinel.adapter.dubbo.fallback; import com.alibaba.csp.sentinel.slots.block.BlockException; -import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; + import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -30,6 +30,6 @@ public class DefaultDubboFallback implements DubboFallback { @Override public Result handle(Invoker invoker, Invocation invocation, BlockException ex) { // Just wrap the exception. - return AsyncRpcResult.newDefaultAsyncResult(null, new SentinelRpcException(ex), invocation); + return AsyncRpcResult.newDefaultAsyncResult(ex.toRuntimeException(), invocation); } } diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java index 9c887c13d3..a9fb1f5a44 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java @@ -16,18 +16,14 @@ package com.alibaba.csp.sentinel.adapter.dubbo.fallback; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig; -import com.alibaba.csp.sentinel.util.AssertUtil; /** *

Global fallback registry for Dubbo.

* - *

- * Note: Circuit breaking is mainly designed for consumer. The provider should not - * give fallback result in most circumstances. - *

- * * @author Eric Zhao + * @deprecated use {@link DubboAdapterGlobalConfig} instead since 1.8.0. */ +@Deprecated public final class DubboFallbackRegistry { public static DubboFallback getConsumerFallback() { @@ -35,7 +31,6 @@ public static DubboFallback getConsumerFallback() { } public static void setConsumerFallback(DubboFallback consumerFallback) { - AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null"); DubboAdapterGlobalConfig.setConsumerFallback(consumerFallback); } @@ -44,7 +39,6 @@ public static DubboFallback getProviderFallback() { } public static void setProviderFallback(DubboFallback providerFallback) { - AssertUtil.notNull(providerFallback, "providerFallback cannot be null"); DubboAdapterGlobalConfig.setProviderFallback(providerFallback); } diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java index c97cdbd5cc..a350a47de1 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java @@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.DubboTestUtil; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.context.Context; @@ -34,6 +35,7 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; + import org.apache.dubbo.rpc.*; import org.apache.dubbo.rpc.support.RpcUtils; import org.junit.After; @@ -53,8 +55,7 @@ */ public class SentinelDubboConsumerFilterTest extends BaseTest { - private SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter(); - + private final SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter(); @Before public void setUp() { @@ -67,7 +68,6 @@ public void destroy() { cleanUpAll(); } - @Test public void testInterfaceLevelFollowControlAsync() throws InterruptedException { @@ -105,7 +105,6 @@ public void testDegradeAsync() throws InterruptedException { verifyInvocationStructureForCallFinish(invoker, invocation); assertEquals("normal", result.getValue()); - // inc the clusterNode's exception to trigger the fallback for (int i = 0; i < 5; i++) { invokeDubboRpc(true, invoker, invocation); @@ -153,7 +152,6 @@ public void testDegradeSync() throws InterruptedException { assertNull(context); } - @Test public void testMethodFlowControlAsync() { @@ -175,10 +173,8 @@ public void testMethodFlowControlAsync() { assertEquals("fallback", fallback.getValue()); verifyInvocationStructureForCallFinish(invoker, invocation); - } - @Test public void testInvokeAsync() { @@ -190,7 +186,7 @@ public void testInvokeAsync() { when(result.hasException()).thenReturn(false); when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { verifyInvocationStructureForAsyncCall(invoker, invocation); - return result; + return result; }); consumerFilter.invoke(invoker, invocation); verify(invoker).invoke(invocation); @@ -220,7 +216,6 @@ public void testInvokeSync() { assertNull(context); } - /** * Simply verify invocation structure in memory: * EntranceNode(defaultContextName) @@ -231,7 +226,8 @@ private void verifyInvocationStructure(Invoker invoker, Invocation invocation) { Context context = ContextUtil.getContext(); assertNotNull(context); // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context - // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter + // In actual project, a consumer is usually also a provider, the context will be created by + //SentinelDubboProviderFilter // If consumer is on the top of Dubbo RPC invocation chain, use default context String resourceName = consumerFilter.getMethodName(invoker, invocation, null); assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); @@ -269,7 +265,8 @@ private void verifyInvocationStructure(Invoker invoker, Invocation invocation) { // Verify clusterNode ClusterNode methodClusterNode = methodNode.getClusterNode(); ClusterNode interfaceClusterNode = interfaceNode.getClusterNode(); - assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode + assertNotSame(methodClusterNode, + interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode // As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode Map methodOriginCountMap = methodClusterNode.getOriginCountMap(); @@ -284,7 +281,8 @@ private void verifyInvocationStructureForAsyncCall(Invoker invoker, Invocation i assertNotNull(context); // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context - // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter + // In actual project, a consumer is usually also a provider, the context will be created by + //SentinelDubboProviderFilter // If consumer is on the top of Dubbo RPC invocation chain, use default context String resourceName = consumerFilter.getMethodName(invoker, invocation, null); assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName()); @@ -319,7 +317,8 @@ private void verifyInvocationStructureForAsyncCall(Invoker invoker, Invocation i // Verify clusterNode ClusterNode methodClusterNode = methodNode.getClusterNode(); ClusterNode interfaceClusterNode = interfaceNode.getClusterNode(); - assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode + assertNotSame(methodClusterNode, + interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode // As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode Map methodOriginCountMap = methodClusterNode.getOriginCountMap(); @@ -329,7 +328,6 @@ private void verifyInvocationStructureForAsyncCall(Invoker invoker, Invocation i assertEquals(0, interfaceOriginCountMap.size()); } - private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation invocation) { Context context = ContextUtil.getContext(); assertNull(context); @@ -338,7 +336,6 @@ private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation assertNull(entries); } - private DefaultNode getNode(String resourceName, DefaultNode root) { Queue queue = new LinkedList<>(); @@ -355,7 +352,6 @@ private DefaultNode getNode(String resourceName, DefaultNode root) { return null; } - private void initFlowRule(String resource) { FlowRule flowRule = new FlowRule(resource); flowRule.setCount(1); @@ -367,24 +363,18 @@ private void initFlowRule(String resource) { private void initDegradeRule(String resource) { DegradeRule degradeRule = new DegradeRule(resource) - .setCount(0.5) - .setGrade(DEGRADE_GRADE_EXCEPTION_RATIO); + .setCount(0.5) + .setGrade(DEGRADE_GRADE_EXCEPTION_RATIO); List degradeRules = new ArrayList<>(); degradeRules.add(degradeRule); degradeRule.setTimeWindow(1); DegradeRuleManager.loadRules(degradeRules); } - private void initFallback() { - DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { - @Override - public Result handle(Invoker invoker, Invocation invocation, BlockException ex) { - boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation); - Result fallbackResult = null; - fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation); - return fallbackResult; - } + DubboAdapterGlobalConfig.setConsumerFallback((invoker, invocation, ex) -> { + // boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation); + return AsyncRpcResult.newDefaultAsyncResult("fallback", invocation); }); } @@ -394,13 +384,11 @@ private Result invokeDubboRpc(boolean exception, Invoker invoker, Invocation inv if (InvokeMode.SYNC == invokeMode) { result = exception ? new AppResponse(new Exception("error")) : new AppResponse("normal"); } else { - result = exception ? AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), invocation) : AsyncRpcResult.newDefaultAsyncResult("normal", invocation); + result = exception ? AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), invocation) + : AsyncRpcResult.newDefaultAsyncResult("normal", invocation); } when(invoker.invoke(invocation)).thenReturn(result); return consumerFilter.invoke(invoker, invocation); } - - - } diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java index 9a3bdeb32b..6c2f427c96 100644 --- a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java @@ -17,8 +17,8 @@ import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig; import com.alibaba.csp.sentinel.slots.block.BlockException; -import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; + import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Result; import org.junit.After; @@ -33,12 +33,12 @@ public class DubboFallbackRegistryTest { @Before public void setUp() { - DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback()); + DubboAdapterGlobalConfig.setConsumerFallback(new DefaultDubboFallback()); } @After public void tearDown() { - DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback()); + DubboAdapterGlobalConfig.setConsumerFallback(new DefaultDubboFallback()); } @Test @@ -46,15 +46,17 @@ public void testDefaultFallback() { // Test for default fallback. BlockException ex = new FlowException("xxx"); Result result = new DefaultDubboFallback().handle(null, null, ex); - Assert.assertTrue("The invocation should not fail",result.hasException()); - Assert.assertEquals(SentinelRpcException.class, result.getException().getClass()); + Assert.assertTrue("The result should carry exception", result.hasException()); + Assert.assertTrue(BlockException.isBlockException(result.getException())); + Assert.assertTrue(result.getException().getMessage().contains(ex.getClass().getSimpleName())); } @Test public void testCustomFallback() { BlockException ex = new FlowException("xxx"); DubboAdapterGlobalConfig.setConsumerFallback( - (invoker, invocation, e) -> AsyncRpcResult.newDefaultAsyncResult("Error: " + e.getClass().getName(), invocation)); + (invoker, invocation, e) -> AsyncRpcResult + .newDefaultAsyncResult("Error: " + e.getClass().getName(), invocation)); Result result = DubboAdapterGlobalConfig.getConsumerFallback() .handle(null, null, ex); Assert.assertFalse("The invocation should not fail", result.hasException()); diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/BlockException.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/BlockException.java index ada98383f2..ad972d440c 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/BlockException.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/BlockException.java @@ -23,7 +23,11 @@ */ public abstract class BlockException extends Exception { + private static final int MAX_SEARCH_DEPTH = 10; + public static final String BLOCK_EXCEPTION_FLAG = "SentinelBlockException"; + public static final String BLOCK_EXCEPTION_MSG_PREFIX = "SentinelBlockException: "; + /** *

this constant RuntimeException has no stack trace, just has a message * {@link #BLOCK_EXCEPTION_FLAG} that marks its name. @@ -85,12 +89,18 @@ public void setRuleLimitApp(String ruleLimitApp) { this.ruleLimitApp = ruleLimitApp; } + public RuntimeException toRuntimeException() { + RuntimeException t = new RuntimeException(BLOCK_EXCEPTION_MSG_PREFIX + getClass().getSimpleName()); + t.setStackTrace(sentinelStackTrace); + return t; + } + /** * Check whether the exception is sentinel blocked exception. One exception is sentinel blocked * exception only when: *

    *
  • the exception or its (sub-)cause is {@link BlockException}, or
  • - *
  • the exception's message is or any of its sub-cause's message equals to {@link #BLOCK_EXCEPTION_FLAG}
  • + *
  • the exception's message or any of its sub-cause's message is prefixed by {@link #BLOCK_EXCEPTION_FLAG}
  • *
* * @param t the exception. @@ -103,8 +113,11 @@ public static boolean isBlockException(Throwable t) { int counter = 0; Throwable cause = t; - while (cause != null && counter++ < 50) { - if ((cause instanceof BlockException) || (BLOCK_EXCEPTION_FLAG.equals(cause.getMessage()))) { + while (cause != null && counter++ < MAX_SEARCH_DEPTH) { + if (cause instanceof BlockException) { + return true; + } + if (cause.getMessage() != null && cause.getMessage().startsWith(BLOCK_EXCEPTION_FLAG)) { return true; } cause = cause.getCause();