Fix NPE bug and improve default fallback in Dubbo 2.7.x adapter
- Fix NPE bug in consumer filter (when non-biz error occurred) - Improve default fallback in Dubbo 2.7.x adapter: convert the BlockException to a simple RuntimeException (with necessary message) - Polish code and comments Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
125996d4d1
commit
5905874dd8
|
|
@ -1,4 +1,4 @@
|
||||||
# Sentinel Apache Dubbo Adapter
|
# Sentinel Apache Dubbo Adapter (for 2.7.x+)
|
||||||
|
|
||||||
> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/主流框架的适配#dubbo)。
|
> 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 Sentinel filters are **enabled by default**. Once you add the dependency,
|
||||||
the Dubbo services and methods will become protected resources in Sentinel,
|
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.
|
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:
|
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.
|
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 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 method: resourceName format is `interfaceName:methodSignature`, e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)`
|
||||||
|
|
||||||
## Flow control based on caller
|
## Flow control based on caller
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,10 @@ import org.apache.dubbo.rpc.Invocation;
|
||||||
import org.apache.dubbo.rpc.Invoker;
|
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
|
* @author Zechao Zheng
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public abstract class BaseSentinelDubboFilter implements Filter {
|
public abstract class BaseSentinelDubboFilter implements Filter {
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,13 @@ import com.alibaba.csp.sentinel.*;
|
||||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
|
||||||
import org.apache.dubbo.common.extension.Activate;
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
import org.apache.dubbo.rpc.*;
|
import org.apache.dubbo.rpc.*;
|
||||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||||
|
|
@ -38,6 +40,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||||
*
|
*
|
||||||
* @author Carpenter Lee
|
* @author Carpenter Lee
|
||||||
* @author Eric Zhao
|
* @author Eric Zhao
|
||||||
|
* @author Lin Liang
|
||||||
*/
|
*/
|
||||||
@Activate(group = CONSUMER)
|
@Activate(group = CONSUMER)
|
||||||
public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
||||||
|
|
@ -64,7 +67,6 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
||||||
} else {
|
} else {
|
||||||
return asyncInvoke(invoker, invocation);
|
return asyncInvoke(invoker, invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result syncInvoke(Invoker<?> invoker, Invocation invocation) {
|
private Result syncInvoke(Invoker<?> invoker, Invocation invocation) {
|
||||||
|
|
@ -75,7 +77,8 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
||||||
String methodResourceName = getMethodName(invoker, invocation, prefix);
|
String methodResourceName = getMethodName(invoker, invocation, prefix);
|
||||||
try {
|
try {
|
||||||
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
|
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);
|
Result result = invoker.invoke(invocation);
|
||||||
if (result.hasException()) {
|
if (result.hasException()) {
|
||||||
Tracer.traceEntry(result.getException(), interfaceEntry);
|
Tracer.traceEntry(result.getException(), interfaceEntry);
|
||||||
|
|
@ -98,24 +101,27 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Result asyncInvoke(Invoker<?> invoker, Invocation invocation) {
|
private Result asyncInvoke(Invoker<?> invoker, Invocation invocation) {
|
||||||
LinkedList<EntryHolder> queue = new LinkedList<>();
|
LinkedList<EntryHolder> queue = new LinkedList<>();
|
||||||
String prefix = DubboAdapterGlobalConfig.getDubboConsumerResNamePrefixKey();
|
String prefix = DubboAdapterGlobalConfig.getDubboConsumerResNamePrefixKey();
|
||||||
String interfaceResourceName = getInterfaceName(invoker, prefix);
|
String interfaceResourceName = getInterfaceName(invoker, prefix);
|
||||||
String methodResourceName = getMethodName(invoker, invocation, prefix);
|
String methodResourceName = getMethodName(invoker, invocation, prefix);
|
||||||
try {
|
try {
|
||||||
queue.push(new EntryHolder(SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT), null));
|
queue.push(new EntryHolder(
|
||||||
queue.push(new EntryHolder(SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments()), invocation.getArguments()));
|
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 result = invoker.invoke(invocation);
|
||||||
result.whenCompleteWithContext(new BiConsumer<Result, Throwable>() {
|
result.whenCompleteWithContext((r, throwable) -> {
|
||||||
@Override
|
Throwable error = throwable;
|
||||||
public void accept(Result result, Throwable throwable) {
|
if (error == null) {
|
||||||
while (!queue.isEmpty()) {
|
error = Optional.ofNullable(r).map(Result::getException).orElse(null);
|
||||||
EntryHolder holder = queue.pop();
|
}
|
||||||
Tracer.traceEntry(result.getException(), holder.entry);
|
while (!queue.isEmpty()) {
|
||||||
exitEntry(holder);
|
EntryHolder holder = queue.pop();
|
||||||
}
|
Tracer.traceEntry(error, holder.entry);
|
||||||
|
exitEntry(holder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -127,10 +133,9 @@ public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EntryHolder {
|
static class EntryHolder {
|
||||||
|
|
||||||
final private Entry entry;
|
final private Entry entry;
|
||||||
|
|
||||||
final private Object[] params;
|
final private Object[] params;
|
||||||
|
|
||||||
public EntryHolder(Entry entry, Object[] params) {
|
public EntryHolder(Entry entry, Object[] params) {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
|
||||||
import org.apache.dubbo.common.extension.Activate;
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
import org.apache.dubbo.rpc.Invocation;
|
import org.apache.dubbo.rpc.Invocation;
|
||||||
import org.apache.dubbo.rpc.Invoker;
|
import org.apache.dubbo.rpc.Invoker;
|
||||||
|
|
@ -74,7 +75,8 @@ public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter {
|
||||||
// at entrance of invocation chain only (for inbound traffic).
|
// at entrance of invocation chain only (for inbound traffic).
|
||||||
ContextUtil.enter(methodResourceName, origin);
|
ContextUtil.enter(methodResourceName, origin);
|
||||||
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
|
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);
|
Result result = invoker.invoke(invocation);
|
||||||
if (result.hasException()) {
|
if (result.hasException()) {
|
||||||
Tracer.traceEntry(result.getException(), interfaceEntry);
|
Tracer.traceEntry(result.getException(), interfaceEntry);
|
||||||
|
|
@ -98,6 +100,5 @@ public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,11 @@ public final class DubboAdapterGlobalConfig {
|
||||||
private static final String DEFAULT_DUBBO_CONSUMER_PREFIX = "dubbo:consumer:";
|
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 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 consumerFallback = new DefaultDubboFallback();
|
||||||
private static volatile DubboFallback providerFallback = new DefaultDubboFallback();
|
private static volatile DubboFallback providerFallback = new DefaultDubboFallback();
|
||||||
private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser();
|
private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser();
|
||||||
|
|
||||||
|
|
||||||
public static boolean isUsePrefix() {
|
public static boolean isUsePrefix() {
|
||||||
return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY));
|
return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY));
|
||||||
}
|
}
|
||||||
|
|
@ -74,16 +72,6 @@ public final class DubboAdapterGlobalConfig {
|
||||||
return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED));
|
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() {
|
public static DubboFallback getConsumerFallback() {
|
||||||
return consumerFallback;
|
return consumerFallback;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
|
package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
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.AsyncRpcResult;
|
||||||
import org.apache.dubbo.rpc.Invocation;
|
import org.apache.dubbo.rpc.Invocation;
|
||||||
import org.apache.dubbo.rpc.Invoker;
|
import org.apache.dubbo.rpc.Invoker;
|
||||||
|
|
@ -30,6 +30,6 @@ public class DefaultDubboFallback implements DubboFallback {
|
||||||
@Override
|
@Override
|
||||||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
|
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
|
||||||
// Just wrap the exception.
|
// Just wrap the exception.
|
||||||
return AsyncRpcResult.newDefaultAsyncResult(null, new SentinelRpcException(ex), invocation);
|
return AsyncRpcResult.newDefaultAsyncResult(ex.toRuntimeException(), invocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,14 @@
|
||||||
package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
|
package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Global fallback registry for Dubbo.</p>
|
* <p>Global fallback registry for Dubbo.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* Note: Circuit breaking is mainly designed for consumer. The provider should not
|
|
||||||
* give fallback result in most circumstances.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Eric Zhao
|
* @author Eric Zhao
|
||||||
|
* @deprecated use {@link DubboAdapterGlobalConfig} instead since 1.8.0.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class DubboFallbackRegistry {
|
public final class DubboFallbackRegistry {
|
||||||
|
|
||||||
public static DubboFallback getConsumerFallback() {
|
public static DubboFallback getConsumerFallback() {
|
||||||
|
|
@ -35,7 +31,6 @@ public final class DubboFallbackRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setConsumerFallback(DubboFallback consumerFallback) {
|
public static void setConsumerFallback(DubboFallback consumerFallback) {
|
||||||
AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
|
|
||||||
DubboAdapterGlobalConfig.setConsumerFallback(consumerFallback);
|
DubboAdapterGlobalConfig.setConsumerFallback(consumerFallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +39,6 @@ public final class DubboFallbackRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setProviderFallback(DubboFallback providerFallback) {
|
public static void setProviderFallback(DubboFallback providerFallback) {
|
||||||
AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
|
|
||||||
DubboAdapterGlobalConfig.setProviderFallback(providerFallback);
|
DubboAdapterGlobalConfig.setProviderFallback(providerFallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.BaseTest;
|
||||||
import com.alibaba.csp.sentinel.DubboTestUtil;
|
import com.alibaba.csp.sentinel.DubboTestUtil;
|
||||||
import com.alibaba.csp.sentinel.Entry;
|
import com.alibaba.csp.sentinel.Entry;
|
||||||
import com.alibaba.csp.sentinel.EntryType;
|
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.DubboFallback;
|
||||||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
|
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
|
||||||
import com.alibaba.csp.sentinel.context.Context;
|
import com.alibaba.csp.sentinel.context.Context;
|
||||||
|
|
@ -34,6 +35,7 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
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.FlowRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.*;
|
import org.apache.dubbo.rpc.*;
|
||||||
import org.apache.dubbo.rpc.support.RpcUtils;
|
import org.apache.dubbo.rpc.support.RpcUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
@ -53,8 +55,7 @@ import static org.mockito.Mockito.*;
|
||||||
*/
|
*/
|
||||||
public class SentinelDubboConsumerFilterTest extends BaseTest {
|
public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
|
|
||||||
private SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter();
|
private final SentinelDubboConsumerFilter consumerFilter = new SentinelDubboConsumerFilter();
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
@ -67,7 +68,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
cleanUpAll();
|
cleanUpAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInterfaceLevelFollowControlAsync() throws InterruptedException {
|
public void testInterfaceLevelFollowControlAsync() throws InterruptedException {
|
||||||
|
|
||||||
|
|
@ -105,7 +105,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
verifyInvocationStructureForCallFinish(invoker, invocation);
|
verifyInvocationStructureForCallFinish(invoker, invocation);
|
||||||
assertEquals("normal", result.getValue());
|
assertEquals("normal", result.getValue());
|
||||||
|
|
||||||
|
|
||||||
// inc the clusterNode's exception to trigger the fallback
|
// inc the clusterNode's exception to trigger the fallback
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
invokeDubboRpc(true, invoker, invocation);
|
invokeDubboRpc(true, invoker, invocation);
|
||||||
|
|
@ -153,7 +152,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertNull(context);
|
assertNull(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMethodFlowControlAsync() {
|
public void testMethodFlowControlAsync() {
|
||||||
|
|
||||||
|
|
@ -175,10 +173,8 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertEquals("fallback", fallback.getValue());
|
assertEquals("fallback", fallback.getValue());
|
||||||
verifyInvocationStructureForCallFinish(invoker, invocation);
|
verifyInvocationStructureForCallFinish(invoker, invocation);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvokeAsync() {
|
public void testInvokeAsync() {
|
||||||
|
|
||||||
|
|
@ -190,7 +186,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
when(result.hasException()).thenReturn(false);
|
when(result.hasException()).thenReturn(false);
|
||||||
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
|
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
|
||||||
verifyInvocationStructureForAsyncCall(invoker, invocation);
|
verifyInvocationStructureForAsyncCall(invoker, invocation);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
consumerFilter.invoke(invoker, invocation);
|
consumerFilter.invoke(invoker, invocation);
|
||||||
verify(invoker).invoke(invocation);
|
verify(invoker).invoke(invocation);
|
||||||
|
|
@ -220,7 +216,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertNull(context);
|
assertNull(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simply verify invocation structure in memory:
|
* Simply verify invocation structure in memory:
|
||||||
* EntranceNode(defaultContextName)
|
* EntranceNode(defaultContextName)
|
||||||
|
|
@ -231,7 +226,8 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
Context context = ContextUtil.getContext();
|
Context context = ContextUtil.getContext();
|
||||||
assertNotNull(context);
|
assertNotNull(context);
|
||||||
// As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default 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
|
// If consumer is on the top of Dubbo RPC invocation chain, use default context
|
||||||
String resourceName = consumerFilter.getMethodName(invoker, invocation, null);
|
String resourceName = consumerFilter.getMethodName(invoker, invocation, null);
|
||||||
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
|
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
|
||||||
|
|
@ -269,7 +265,8 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
// Verify clusterNode
|
// Verify clusterNode
|
||||||
ClusterNode methodClusterNode = methodNode.getClusterNode();
|
ClusterNode methodClusterNode = methodNode.getClusterNode();
|
||||||
ClusterNode interfaceClusterNode = interfaceNode.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
|
// As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
|
||||||
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
|
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
|
||||||
|
|
@ -284,7 +281,8 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertNotNull(context);
|
assertNotNull(context);
|
||||||
|
|
||||||
// As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default 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
|
// If consumer is on the top of Dubbo RPC invocation chain, use default context
|
||||||
String resourceName = consumerFilter.getMethodName(invoker, invocation, null);
|
String resourceName = consumerFilter.getMethodName(invoker, invocation, null);
|
||||||
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
|
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
|
||||||
|
|
@ -319,7 +317,8 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
// Verify clusterNode
|
// Verify clusterNode
|
||||||
ClusterNode methodClusterNode = methodNode.getClusterNode();
|
ClusterNode methodClusterNode = methodNode.getClusterNode();
|
||||||
ClusterNode interfaceClusterNode = interfaceNode.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
|
// As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
|
||||||
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
|
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
|
||||||
|
|
@ -329,7 +328,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertEquals(0, interfaceOriginCountMap.size());
|
assertEquals(0, interfaceOriginCountMap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation invocation) {
|
private void verifyInvocationStructureForCallFinish(Invoker invoker, Invocation invocation) {
|
||||||
Context context = ContextUtil.getContext();
|
Context context = ContextUtil.getContext();
|
||||||
assertNull(context);
|
assertNull(context);
|
||||||
|
|
@ -338,7 +336,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
assertNull(entries);
|
assertNull(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private DefaultNode getNode(String resourceName, DefaultNode root) {
|
private DefaultNode getNode(String resourceName, DefaultNode root) {
|
||||||
|
|
||||||
Queue<DefaultNode> queue = new LinkedList<>();
|
Queue<DefaultNode> queue = new LinkedList<>();
|
||||||
|
|
@ -355,7 +352,6 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initFlowRule(String resource) {
|
private void initFlowRule(String resource) {
|
||||||
FlowRule flowRule = new FlowRule(resource);
|
FlowRule flowRule = new FlowRule(resource);
|
||||||
flowRule.setCount(1);
|
flowRule.setCount(1);
|
||||||
|
|
@ -367,24 +363,18 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
|
|
||||||
private void initDegradeRule(String resource) {
|
private void initDegradeRule(String resource) {
|
||||||
DegradeRule degradeRule = new DegradeRule(resource)
|
DegradeRule degradeRule = new DegradeRule(resource)
|
||||||
.setCount(0.5)
|
.setCount(0.5)
|
||||||
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO);
|
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO);
|
||||||
List<DegradeRule> degradeRules = new ArrayList<>();
|
List<DegradeRule> degradeRules = new ArrayList<>();
|
||||||
degradeRules.add(degradeRule);
|
degradeRules.add(degradeRule);
|
||||||
degradeRule.setTimeWindow(1);
|
degradeRule.setTimeWindow(1);
|
||||||
DegradeRuleManager.loadRules(degradeRules);
|
DegradeRuleManager.loadRules(degradeRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void initFallback() {
|
private void initFallback() {
|
||||||
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() {
|
DubboAdapterGlobalConfig.setConsumerFallback((invoker, invocation, ex) -> {
|
||||||
@Override
|
// boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation);
|
||||||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
|
return AsyncRpcResult.newDefaultAsyncResult("fallback", invocation);
|
||||||
boolean async = RpcUtils.isAsync(invoker.getUrl(), invocation);
|
|
||||||
Result fallbackResult = null;
|
|
||||||
fallbackResult = AsyncRpcResult.newDefaultAsyncResult("fallback", invocation);
|
|
||||||
return fallbackResult;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,13 +384,11 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
|
||||||
if (InvokeMode.SYNC == invokeMode) {
|
if (InvokeMode.SYNC == invokeMode) {
|
||||||
result = exception ? new AppResponse(new Exception("error")) : new AppResponse("normal");
|
result = exception ? new AppResponse(new Exception("error")) : new AppResponse("normal");
|
||||||
} else {
|
} 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);
|
when(invoker.invoke(invocation)).thenReturn(result);
|
||||||
return consumerFilter.invoke(invoker, invocation);
|
return consumerFilter.invoke(invoker, invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ package com.alibaba.csp.sentinel.adapter.dubbo.fallback;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
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 com.alibaba.csp.sentinel.slots.block.flow.FlowException;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||||
import org.apache.dubbo.rpc.Result;
|
import org.apache.dubbo.rpc.Result;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
@ -33,12 +33,12 @@ public class DubboFallbackRegistryTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback());
|
DubboAdapterGlobalConfig.setConsumerFallback(new DefaultDubboFallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
DubboFallbackRegistry.setConsumerFallback(new DefaultDubboFallback());
|
DubboAdapterGlobalConfig.setConsumerFallback(new DefaultDubboFallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -46,15 +46,17 @@ public class DubboFallbackRegistryTest {
|
||||||
// Test for default fallback.
|
// Test for default fallback.
|
||||||
BlockException ex = new FlowException("xxx");
|
BlockException ex = new FlowException("xxx");
|
||||||
Result result = new DefaultDubboFallback().handle(null, null, ex);
|
Result result = new DefaultDubboFallback().handle(null, null, ex);
|
||||||
Assert.assertTrue("The invocation should not fail",result.hasException());
|
Assert.assertTrue("The result should carry exception", result.hasException());
|
||||||
Assert.assertEquals(SentinelRpcException.class, result.getException().getClass());
|
Assert.assertTrue(BlockException.isBlockException(result.getException()));
|
||||||
|
Assert.assertTrue(result.getException().getMessage().contains(ex.getClass().getSimpleName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomFallback() {
|
public void testCustomFallback() {
|
||||||
BlockException ex = new FlowException("xxx");
|
BlockException ex = new FlowException("xxx");
|
||||||
DubboAdapterGlobalConfig.setConsumerFallback(
|
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()
|
Result result = DubboAdapterGlobalConfig.getConsumerFallback()
|
||||||
.handle(null, null, ex);
|
.handle(null, null, ex);
|
||||||
Assert.assertFalse("The invocation should not fail", result.hasException());
|
Assert.assertFalse("The invocation should not fail", result.hasException());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue