Browse Source

Improve async invocation support in sentinel-apache-dubbo-adapter (#1124)

* Improve async support for Dubbo 2.7.2 and above (not compatible with 2.7.0 and 2.7.1 due to the bad compatibility design of Dubbo Filter)
master
Mr.Z Eric Zhao 5 years ago
parent
commit
47100e64ba
21 changed files with 798 additions and 130 deletions
  1. +1
    -1
      sentinel-adapter/sentinel-apache-dubbo-adapter/pom.xml
  2. +77
    -0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java
  3. +2
    -2
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java
  4. +15
    -8
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java
  5. +22
    -25
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java
  6. +15
    -31
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java
  7. +16
    -1
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboConfig.java
  8. +52
    -5
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java
  9. +34
    -6
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java
  10. +282
    -18
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java
  11. +21
    -12
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java
  12. +2
    -3
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java
  13. +1
    -0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java
  14. +5
    -0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java
  15. +1
    -1
      sentinel-demo/sentinel-demo-apache-dubbo/pom.xml
  16. +108
    -2
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooConsumerBootstrap.java
  17. +119
    -0
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooConsumerExceptionDegradeBootstrap.java
  18. +0
    -10
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooProviderBootstrap.java
  19. +2
    -0
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooService.java
  20. +5
    -2
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/FooServiceConsumer.java
  21. +18
    -3
      sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/FooServiceImpl.java

+ 1
- 1
sentinel-adapter/sentinel-apache-dubbo-adapter/pom.xml View File

@@ -15,7 +15,7 @@
<properties> <properties>
<java.source.version>1.8</java.source.version> <java.source.version>1.8</java.source.version>
<java.target.version>1.8</java.target.version> <java.target.version>1.8</java.target.version>
<apache.dubbo.version>2.7.1</apache.dubbo.version>
<apache.dubbo.version>2.7.3</apache.dubbo.version>
</properties> </properties>


<dependencies> <dependencies>


+ 77
- 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java View File

@@ -0,0 +1,77 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.adapter.dubbo;


import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.context.ContextUtil;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.ListenableFilter;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;

/**
* Base Class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}.
*
* @author Zechao Zheng
*/

public abstract class BaseSentinelDubboFilter extends ListenableFilter {
public BaseSentinelDubboFilter() {
this.listener = new SentinelDubboListener();
}

static class SentinelDubboListener implements Listener {

@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
if (DubboConfig.getDubboBizExceptionTraceEnabled()) {
traceAndExit(appResponse.getException(), invoker.getUrl());
} else {
traceAndExit(null, invoker.getUrl());
}
}

@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
traceAndExit(t, invoker.getUrl());
}

}

static void traceAndExit(Throwable throwable, URL url) {
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
if (methodEntry != null) {
Tracer.traceEntry(throwable, methodEntry);
methodEntry.exit();
RpcContext.getContext().remove(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
}
if (interfaceEntry != null) {
Tracer.traceEntry(throwable, interfaceEntry);
interfaceEntry.exit();
RpcContext.getContext().remove(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
}
if (CommonConstants.PROVIDER_SIDE.equals(url.getParameter(CommonConstants.SIDE_KEY))) {
ContextUtil.exit();
}
}
}

+ 2
- 2
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java View File

@@ -15,7 +15,7 @@
*/ */
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;


import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
@@ -34,7 +34,7 @@ public class DubboAppContextFilter implements Filter {


@Override @Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
String application = invoker.getUrl().getParameter(CommonConstants.APPLICATION_KEY);
if (application != null) { if (application != null) {
RpcContext.getContext().setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, application); RpcContext.getContext().setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, application);
} }


+ 15
- 8
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java View File

@@ -15,6 +15,7 @@
*/ */
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;


import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
@@ -25,6 +26,8 @@ import org.apache.dubbo.rpc.Invoker;
public final class DubboUtils { public final class DubboUtils {


public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication"; public static final String SENTINEL_DUBBO_APPLICATION_KEY = "dubboApplication";
public static final String DUBBO_METHOD_ENTRY_KEY = "dubboMethodEntry";
public static final String DUBBO_INTERFACE_ENTRY_KEY = "dubboInterfaceEntry";


public static String getApplication(Invocation invocation, String defaultValue) { public static String getApplication(Invocation invocation, String defaultValue) {
if (invocation == null || invocation.getAttachments() == null) { if (invocation == null || invocation.getAttachments() == null) {
@@ -33,12 +36,17 @@ public final class DubboUtils {
return invocation.getAttachment(SENTINEL_DUBBO_APPLICATION_KEY, defaultValue); return invocation.getAttachment(SENTINEL_DUBBO_APPLICATION_KEY, defaultValue);
} }


public static String getResourceName(Invoker<?> invoker, Invocation invocation) {
public static String getResourceName(Invoker<?> invoker, Invocation invocation){
return getResourceName(invoker, invocation, false);
}

public static String getResourceName(Invoker<?> invoker, Invocation invocation, Boolean useGroupAndVersion) {
StringBuilder buf = new StringBuilder(64); StringBuilder buf = new StringBuilder(64);
buf.append(invoker.getInterface().getName())
.append(":")
.append(invocation.getMethodName())
.append("(");
String interfaceResource = useGroupAndVersion ? invoker.getUrl().getColonSeparatedKey() : invoker.getInterface().getName();
buf.append(interfaceResource)
.append(":")
.append(invocation.getMethodName())
.append("(");
boolean isFirst = true; boolean isFirst = true;
for (Class<?> clazz : invocation.getParameterTypes()) { for (Class<?> clazz : invocation.getParameterTypes()) {
if (!isFirst) { if (!isFirst) {
@@ -55,13 +63,12 @@ public final class DubboUtils {
if (StringUtil.isNotBlank(prefix)) { if (StringUtil.isNotBlank(prefix)) {
return new StringBuilder(64) return new StringBuilder(64)
.append(prefix) .append(prefix)
.append(getResourceName(invoker, invocation))
.append(getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled()))
.toString(); .toString();
} else { } else {
return getResourceName(invoker, invocation);
return getResourceName(invoker, invocation, DubboConfig.getDubboInterfaceGroupAndVersionEnabled());
} }
} }

private DubboUtils() { private DubboUtils() {
} }
} }

+ 22
- 25
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java View File

@@ -19,17 +19,18 @@ import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
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.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.InvokeMode;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.support.RpcUtils;


/** /**
* <p>Dubbo service consumer filter for Sentinel. Auto activated by default.</p> * <p>Dubbo service consumer filter for Sentinel. Auto activated by default.</p>
@@ -43,7 +44,7 @@ import org.apache.dubbo.rpc.RpcException;
* @author Eric Zhao * @author Eric Zhao
*/ */
@Activate(group = "consumer") @Activate(group = "consumer")
public class SentinelDubboConsumerFilter implements Filter {
public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {


public SentinelDubboConsumerFilter() { public SentinelDubboConsumerFilter() {
RecordLog.info("Sentinel Apache Dubbo consumer filter initialized"); RecordLog.info("Sentinel Apache Dubbo consumer filter initialized");
@@ -53,33 +54,29 @@ public class SentinelDubboConsumerFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Entry interfaceEntry = null; Entry interfaceEntry = null;
Entry methodEntry = null; Entry methodEntry = null;
RpcContext rpcContext = RpcContext.getContext();
try { try {
String resourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
interfaceEntry = SphU.entry(invoker.getInterface().getName(),
ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation);


Result result = invoker.invoke(invocation);
if (result.hasException()) {
Throwable e = result.getException();
// Record common exception.
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
if (InvokeMode.SYNC == invokeMode) {
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments());
} else {
// should generate the AsyncEntry when the invoke model in future or async
interfaceEntry = SphU.asyncEntry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.asyncEntry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, 1, invocation.getArguments());
} }
return result;
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
return invoker.invoke(invocation);
} catch (BlockException e) { } catch (BlockException e) {
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);
} catch (RpcException e) {
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
throw e;
} finally {
if (methodEntry != null) {
methodEntry.exit();
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
} }
} }
} }



+ 15
- 31
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java View File

@@ -19,17 +19,16 @@ import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
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.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;


/** /**
@@ -45,7 +44,7 @@ import org.apache.dubbo.rpc.RpcException;
* @author Eric Zhao * @author Eric Zhao
*/ */
@Activate(group = "provider") @Activate(group = "provider")
public class SentinelDubboProviderFilter implements Filter {
public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter {


public SentinelDubboProviderFilter() { public SentinelDubboProviderFilter() {
RecordLog.info("Sentinel Apache Dubbo provider filter initialized"); RecordLog.info("Sentinel Apache Dubbo provider filter initialized");
@@ -55,41 +54,26 @@ public class SentinelDubboProviderFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// Get origin caller. // Get origin caller.
String application = DubboUtils.getApplication(invocation, ""); String application = DubboUtils.getApplication(invocation, "");
RpcContext rpcContext = RpcContext.getContext();
Entry interfaceEntry = null; Entry interfaceEntry = null;
Entry methodEntry = null; Entry methodEntry = null;
try { try {
String resourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());
String interfaceName = invoker.getInterface().getName();
String methodResourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());
String interfaceResourceName = DubboConfig.getDubboInterfaceGroupAndVersionEnabled() ? invoker.getUrl().getColonSeparatedKey()
: invoker.getInterface().getName();
// Only need to create entrance context at provider side, as context will take effect // Only need to create entrance context at provider side, as context will take effect
// at entrance of invocation chain only (for inbound traffic). // at entrance of invocation chain only (for inbound traffic).
ContextUtil.enter(resourceName, application);
interfaceEntry = SphU.entry(interfaceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC,
EntryType.IN, invocation.getArguments());

Result result = invoker.invoke(invocation);
if (result.hasException()) {
Throwable e = result.getException();
// Record common exception.
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
}
return result;
ContextUtil.enter(methodResourceName, application);
interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
rpcContext.set(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY, interfaceEntry);
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, invocation.getArguments());
rpcContext.set(DubboUtils.DUBBO_METHOD_ENTRY_KEY, methodEntry);
return invoker.invoke(invocation);
} catch (BlockException e) { } catch (BlockException e) {
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
} catch (RpcException e) {
Tracer.traceEntry(e, interfaceEntry);
Tracer.traceEntry(e, methodEntry);
throw e;
} finally {
if (methodEntry != null) {
methodEntry.exit(1, invocation.getArguments());
}
if (interfaceEntry != null) {
interfaceEntry.exit();
}
ContextUtil.exit();
} }
} }


} }


+ 16
- 1
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboConfig.java View File

@@ -37,8 +37,12 @@ public final class DubboConfig {
private static final String DEFAULT_DUBBO_PROVIDER_PREFIX = "dubbo:provider:"; private static final String DEFAULT_DUBBO_PROVIDER_PREFIX = "dubbo:provider:";
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 boolean isUsePrefix(){
public static final String TRACE_BIZ_EXCEPTION_ENABLED = "csp.sentinel.dubbo.trace.biz.exception.enabled";


public static boolean isUsePrefix() {
return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_USE_PREFIX)); return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_USE_PREFIX));
} }


@@ -58,5 +62,16 @@ public final class DubboConfig {
return null; return null;
} }


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;
}


} }

+ 52
- 5
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java View File

@@ -15,26 +15,73 @@
*/ */
package com.alibaba.csp.sentinel; package com.alibaba.csp.sentinel;


import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/** /**
* Base test class, provide common methods for subClass * Base test class, provide common methods for subClass
* The package is same as CtSph, to call CtSph.resetChainMap() method for test * The package is same as CtSph, to call CtSph.resetChainMap() method for test
*
* <p>
* Note: Only for test. DO NOT USE IN PRODUCTION! * Note: Only for test. DO NOT USE IN PRODUCTION!
* *
* @author cdfive * @author cdfive
*/ */
public class BaseTest { public class BaseTest {



protected Invoker invoker;
protected Invocation invocation;

public void constructInvokerAndInvocation() {
invoker = mock(Invoker.class);
URL url = URL.valueOf("dubbo://127.0.0.1:2181")
.addParameter(CommonConstants.VERSION_KEY, "1.0.0")
.addParameter(CommonConstants.GROUP_KEY, "grp1")
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName());
when(invoker.getUrl()).thenReturn(url);
when(invoker.getInterface()).thenReturn(DemoService.class);

invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());

}

/** /**
* Clean up resources for context, clusterNodeMap, processorSlotChainMap * Clean up resources for context, clusterNodeMap, processorSlotChainMap
*/ */
protected static void cleanUpAll() { protected static void cleanUpAll() {
RpcContext.removeContext();
ClusterBuilderSlot.getClusterNodeMap().clear();
CtSph.resetChainMap();
try {
RpcContext.removeContext();
ClusterBuilderSlot.getClusterNodeMap().clear();
CtSph.resetChainMap();
Method method = ContextUtil.class.getDeclaredMethod("resetContextMap");
method.setAccessible(true);
method.invoke(null, null);
ContextUtil.exit();
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "true");
FlowRuleManager.loadRules(new ArrayList<>());
DegradeRuleManager.loadRules(new ArrayList<>());
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} }
} }

+ 34
- 6
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java View File

@@ -18,6 +18,8 @@ package com.alibaba.csp.sentinel.adapter.dubbo;
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig;
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.junit.After; import org.junit.After;
@@ -29,7 +31,9 @@ import java.util.HashMap;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


/** /**
* @author cdfive * @author cdfive
@@ -41,6 +45,7 @@ public class DubboUtilsTest {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true"); SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
} }




@@ -49,6 +54,7 @@ public class DubboUtilsTest {
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false");
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "");
SentinelConfig.setConfig(DubboConfig.DUBBO_INTERFACE_GROUP_VERSION_ENABLED, "false");
} }




@@ -78,27 +84,49 @@ public class DubboUtilsTest {
} }


@Test @Test
public void testGetResourceName() {
public void testGetResourceName() throws NoSuchMethodException {
Invoker invoker = mock(Invoker.class); Invoker invoker = mock(Invoker.class);
when(invoker.getInterface()).thenReturn(DemoService.class); when(invoker.getInterface()).thenReturn(DemoService.class);


Invocation invocation = mock(Invocation.class); Invocation invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
Method method = DemoService.class.getDeclaredMethod("sayHello", String.class, int.class);
when(invocation.getMethodName()).thenReturn(method.getName()); when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());


String resourceName = DubboUtils.getResourceName(invoker, invocation); String resourceName = DubboUtils.getResourceName(invoker, invocation);


assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);

} }


@Test @Test
public void testGetResourceNameWithPrefix() {
public void testGetResourceNameWithGroupAndVersion() throws NoSuchMethodException {
Invoker invoker = mock(Invoker.class);
URL url = URL.valueOf("dubbo://127.0.0.1:2181")
.addParameter(CommonConstants.VERSION_KEY, "1.0.0")
.addParameter(CommonConstants.GROUP_KEY, "grp1")
.addParameter(CommonConstants.INTERFACE_KEY, DemoService.class.getName());
when(invoker.getUrl()).thenReturn(url);
when(invoker.getInterface()).thenReturn(DemoService.class);

Invocation invocation = mock(Invocation.class);
Method method = DemoService.class.getDeclaredMethod("sayHello", String.class, int.class);
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());

String resourceNameUseGroupAndVersion = DubboUtils.getResourceName(invoker, invocation, true);

assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:1.0.0:grp1:sayHello(java.lang.String,int)", resourceNameUseGroupAndVersion);
}


@Test
public void testGetResourceNameWithPrefix() throws NoSuchMethodException {
Invoker invoker = mock(Invoker.class); Invoker invoker = mock(Invoker.class);
when(invoker.getInterface()).thenReturn(DemoService.class); when(invoker.getInterface()).thenReturn(DemoService.class);


Invocation invocation = mock(Invocation.class); Invocation invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
Method method = DemoService.class.getDeclaredMethod("sayHello", String.class, int.class);
when(invocation.getMethodName()).thenReturn(method.getName()); when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());


@@ -118,4 +146,4 @@ public class DubboUtilsTest {
assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);


} }
}
}

+ 282
- 18
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java View File

@@ -16,9 +16,11 @@
package com.alibaba.csp.sentinel.adapter.dubbo; package com.alibaba.csp.sentinel.adapter.dubbo;


import com.alibaba.csp.sentinel.BaseTest; import com.alibaba.csp.sentinel.BaseTest;
import com.alibaba.csp.sentinel.Constants;
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.DubboConfig;
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.provider.DemoService; import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.context.ContextUtil;
@@ -27,20 +29,40 @@ import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node; import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.node.StatisticNode; import com.alibaba.csp.sentinel.node.StatisticNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
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.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
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;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.support.RpcUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.Set; import java.util.Set;


import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO;
import static org.apache.dubbo.rpc.Constants.ASYNC_KEY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


/** /**
* @author cdfive * @author cdfive
@@ -49,9 +71,12 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {


private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter(); private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter();



@Before @Before
public void setUp() { public void setUp() {
cleanUpAll(); cleanUpAll();
initFallback();
constructInvokerAndInvocation();
} }


@After @After
@@ -59,18 +84,177 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
cleanUpAll(); cleanUpAll();
} }


public void initFlowRule(String resource) {
FlowRule flowRule = new FlowRule(resource);
flowRule.setCount(1);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
List<FlowRule> flowRules = new ArrayList<>();
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}

public void initDegradeRule(String resource) {
DegradeRule degradeRule = new DegradeRule(resource)
.setCount(0.5)
.setGrade(DEGRADE_GRADE_EXCEPTION_RATIO);
List<DegradeRule> degradeRules = new ArrayList<>();
degradeRules.add(degradeRule);
degradeRule.setTimeWindow(1);
DegradeRuleManager.loadRules(degradeRules);
}


public 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;
}
});
}

@Test
public void testInterfaceLevelFollowControlAsync() throws InterruptedException {
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initFlowRule(invoker.getUrl().getColonSeparatedKey());
Result result1 = responseBack(requestGo(false, invocation));
assertEquals("normal", result1.getValue());
// should fallback because the qps > 1
Result result2 = responseBack(requestGo(false, invocation));
assertEquals("fallback", result2.getValue());
// sleeping 1000 ms to reset qps
Thread.sleep(1000);
Result result3 = responseBack(requestGo(false, invocation));
assertEquals("normal", result3.getValue());

verifyInvocationStructureForCallFinish();
}

@Test
public void testDegradeAsync() throws InterruptedException {
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());

initDegradeRule(invoker.getUrl().getColonSeparatedKey());
Result result = requestGo(false, invocation);
verifyInvocationStructureForAsyncCall(invoker, invocation);
responseBack(result);
assertEquals("normal", result.getValue());
// inc the clusterNode's exception to trigger the fallback
for (int i = 0; i < 5; i++) {
responseBack(requestGo(true, invocation));
verifyInvocationStructureForCallFinish();
}
Result result2 = responseBack(requestGo(false, invocation));
assertEquals("fallback", result2.getValue());
// sleeping 1000 ms to reset exception
Thread.sleep(1000);

Result result3 = responseBack(requestGo(false, invocation));
assertEquals("normal", result3.getValue());

Context context = ContextUtil.getContext();
assertNull(context);
}

@Test
public void testDegradeSync() throws InterruptedException {

initDegradeRule(invoker.getUrl().getColonSeparatedKey());
Result result = requestGo(false, invocation);
verifyInvocationStructure(invoker, invocation);
responseBack(result);
assertEquals("normal", result.getValue());
// inc the clusterNode's exception to trigger the fallback
for (int i = 0; i < 5; i++) {
responseBack(requestGo(true, invocation));
verifyInvocationStructureForCallFinish();
}
Result result2 = responseBack(requestGo(false, invocation));
assertEquals("fallback", result2.getValue());
// sleeping 1000 ms to reset exception
Thread.sleep(1000);

Result result3 = responseBack(requestGo(false, invocation));
assertEquals("normal", result3.getValue());

Context context = ContextUtil.getContext();
assertNull(context);
}


@Test
public void testMethodFlowControlAsync() {
when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());
initFlowRule(DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()));
responseBack(requestGo(false, invocation));

responseBack(requestGo(false, invocation));

Invocation invocation2 = mock(Invocation.class);
Method method = DemoService.class.getMethods()[1];
when(invocation2.getMethodName()).thenReturn(method.getName());
when(invocation2.getParameterTypes()).thenReturn(method.getParameterTypes());
Result result2 = responseBack(requestGo(false, invocation2));
verifyInvocationStructureForCallFinish();
assertEquals("normal", result2.getValue());

// the method of invocation should be blocked
Result fallback = requestGo(false, invocation);
assertNotNull(RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY));
assertNull(RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY));
responseBack(fallback);
assertEquals("fallback", fallback.getValue());
verifyInvocationStructureForCallFinish();


}

public Result requestGo(boolean exception, Invocation currentInvocation) {
AsyncRpcResult result = null;

if (exception) {
result = AsyncRpcResult.newDefaultAsyncResult(new Exception("error"), currentInvocation);
} else {
result = AsyncRpcResult.newDefaultAsyncResult("normal", currentInvocation);
}
when(invoker.invoke(currentInvocation)).thenReturn(result);
return filter.invoke(invoker, currentInvocation);
}

public Result responseBack(Result result) {
filter.listener().onResponse(result, invoker, invocation);
return result;
}


@Test @Test
public void testInvoke() {
final Invoker invoker = mock(Invoker.class);
when(invoker.getInterface()).thenReturn(DemoService.class);
public void testInvokeAsync() throws InterruptedException {

when(invocation.getAttachment(ASYNC_KEY)).thenReturn(Boolean.TRUE.toString());

final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false);
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
verifyInvocationStructureForAsyncCall(invoker, invocation);
return result;
});

filter.invoke(invoker, invocation);
verify(invoker).invoke(invocation);

Context context = ContextUtil.getContext();
assertNotNull(context);
}


final Invocation invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
@Test
public void testInvokeSync() {


final Result result = mock(Result.class); final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false); when(result.hasException()).thenReturn(false);
when(result.getException()).thenReturn(new Exception());
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
verifyInvocationStructure(invoker, invocation); verifyInvocationStructure(invoker, invocation);
return result; return result;
@@ -79,6 +263,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
filter.invoke(invoker, invocation); filter.invoke(invoker, invocation);
verify(invoker).invoke(invocation); verify(invoker).invoke(invocation);


filter.listener().onResponse(result, invoker, invocation);
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNull(context); assertNull(context);
} }
@@ -92,31 +277,32 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
private void verifyInvocationStructure(Invoker invoker, Invocation invocation) { private void verifyInvocationStructure(Invoker invoker, Invocation invocation) {
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 = DubboUtils.getResourceName(invoker, invocation);
assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName());
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
assertEquals("", context.getOrigin()); assertEquals("", context.getOrigin());


DefaultNode entranceNode = context.getEntranceNode(); DefaultNode entranceNode = context.getEntranceNode();
ResourceWrapper entranceResource = entranceNode.getId(); ResourceWrapper entranceResource = entranceNode.getId();
assertEquals(Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());

assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());
assertSame(EntryType.IN, entranceResource.getEntryType()); assertSame(EntryType.IN, entranceResource.getEntryType());


// As SphU.entry(interfaceName, EntryType.OUT); // As SphU.entry(interfaceName, EntryType.OUT);
Set<Node> childList = entranceNode.getChildList(); Set<Node> childList = entranceNode.getChildList();
assertEquals(1, childList.size()); assertEquals(1, childList.size());
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode);
ResourceWrapper interfaceResource = interfaceNode.getId(); ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(DemoService.class.getName(), interfaceResource.getName());

assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertSame(EntryType.OUT, interfaceResource.getEntryType()); assertSame(EntryType.OUT, interfaceResource.getEntryType());


// As SphU.entry(resourceName, EntryType.OUT); // As SphU.entry(resourceName, EntryType.OUT);
childList = interfaceNode.getChildList(); childList = interfaceNode.getChildList();
assertEquals(1, childList.size()); assertEquals(1, childList.size());
DefaultNode methodNode = (DefaultNode) childList.iterator().next();
DefaultNode methodNode = getNode(resourceName, entranceNode);
ResourceWrapper methodResource = methodNode.getId(); ResourceWrapper methodResource = methodNode.getId();
assertEquals(resourceName, methodResource.getName()); assertEquals(resourceName, methodResource.getName());
assertSame(EntryType.OUT, methodResource.getEntryType()); assertSame(EntryType.OUT, methodResource.getEntryType());
@@ -139,4 +325,82 @@ public class SentinelDubboConsumerFilterTest extends BaseTest {
Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap(); Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
assertEquals(0, interfaceOriginCountMap.size()); assertEquals(0, interfaceOriginCountMap.size());
} }

private void verifyInvocationStructureForAsyncCall(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
// If consumer is on the top of Dubbo RPC invocation chain, use default context
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, context.getName());
assertEquals("", context.getOrigin());

DefaultNode entranceNode = context.getEntranceNode();
ResourceWrapper entranceResource = entranceNode.getId();
assertEquals(com.alibaba.csp.sentinel.Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());
assertSame(EntryType.IN, entranceResource.getEntryType());

// As SphU.entry(interfaceName, EntryType.OUT);
Set<Node> childList = entranceNode.getChildList();
assertEquals(2, childList.size());
DefaultNode interfaceNode = getNode(invoker.getUrl().getColonSeparatedKey(), entranceNode);
ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertSame(EntryType.OUT, interfaceResource.getEntryType());

// As SphU.entry(resourceName, EntryType.OUT);
childList = interfaceNode.getChildList();
assertEquals(0, childList.size());
DefaultNode methodNode = getNode(resourceName, entranceNode);
ResourceWrapper methodResource = methodNode.getId();
assertEquals(resourceName, methodResource.getName());
assertSame(EntryType.OUT, methodResource.getEntryType());

// Verify curEntry
// nothing will bind to local context when use the AsyncEntry
Entry curEntry = context.getCurEntry();
assertNull(curEntry);

// Verify clusterNode
ClusterNode methodClusterNode = methodNode.getClusterNode();
ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode

// As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
assertEquals(0, methodOriginCountMap.size());

Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
assertEquals(0, interfaceOriginCountMap.size());
}


private void verifyInvocationStructureForCallFinish() {
Context context = ContextUtil.getContext();
assertNull(context);
Entry interfaceEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_INTERFACE_ENTRY_KEY);
Entry methodEntry = (Entry) RpcContext.getContext().get(DubboUtils.DUBBO_METHOD_ENTRY_KEY);
assertNull(interfaceEntry);
assertNull(methodEntry);
}


public DefaultNode getNode(String resourceName, DefaultNode root) {

Queue<DefaultNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
DefaultNode temp = queue.poll();
if (temp.getId().getName().equals(resourceName)) {
return temp;
}
for (Node node : temp.getChildList()) {
queue.offer((DefaultNode) node);
}
}
return null;
}

} }

+ 21
- 12
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilterTest.java View File

@@ -26,7 +26,8 @@ import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node; import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.node.StatisticNode; import com.alibaba.csp.sentinel.node.StatisticNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
@@ -38,8 +39,15 @@ import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;


import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


/** /**
* @author cdfive * @author cdfive
@@ -50,6 +58,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest {


@Before @Before
public void setUp() { public void setUp() {
constructInvokerAndInvocation();
cleanUpAll(); cleanUpAll();
} }


@@ -62,18 +71,16 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
public void testInvoke() { public void testInvoke() {
final String originApplication = "consumerA"; final String originApplication = "consumerA";


final Invoker invoker = mock(Invoker.class);
when(invoker.getInterface()).thenReturn(DemoService.class);
URL url = invoker.getUrl()
.addParameter(CommonConstants.SIDE_KEY, CommonConstants.PROVIDER_SIDE);
when(invoker.getUrl()).thenReturn(url);


final Invocation invocation = mock(Invocation.class);
Method method = DemoService.class.getMethods()[0];
when(invocation.getMethodName()).thenReturn(method.getName());
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "")) when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""))
.thenReturn(originApplication);
.thenReturn(originApplication);


final Result result = mock(Result.class); final Result result = mock(Result.class);
when(result.hasException()).thenReturn(false); when(result.hasException()).thenReturn(false);
when(result.getException()).thenReturn(new Exception());
when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> {
verifyInvocationStructure(originApplication, invoker, invocation); verifyInvocationStructure(originApplication, invoker, invocation);
return result; return result;
@@ -82,6 +89,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
filter.invoke(invoker, invocation); filter.invoke(invoker, invocation);
verify(invoker).invoke(invocation); verify(invoker).invoke(invocation);


filter.listener().onResponse(result, invoker, invocation);
Context context = ContextUtil.getContext(); Context context = ContextUtil.getContext();
assertNull(context); assertNull(context);
} }
@@ -97,7 +105,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
assertNotNull(context); assertNotNull(context);


// As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter // As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter
String resourceName = DubboUtils.getResourceName(invoker, invocation);
String resourceName = DubboUtils.getResourceName(invoker, invocation, true);
assertEquals(resourceName, context.getName()); assertEquals(resourceName, context.getName());
assertEquals(originApplication, context.getOrigin()); assertEquals(originApplication, context.getOrigin());


@@ -111,7 +119,8 @@ public class SentinelDubboProviderFilterTest extends BaseTest {
assertEquals(1, childList.size()); assertEquals(1, childList.size());
DefaultNode interfaceNode = (DefaultNode) childList.iterator().next(); DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
ResourceWrapper interfaceResource = interfaceNode.getId(); ResourceWrapper interfaceResource = interfaceNode.getId();
assertEquals(DemoService.class.getName(), interfaceResource.getName());

assertEquals(invoker.getUrl().getColonSeparatedKey(), interfaceResource.getName());
assertSame(EntryType.IN, interfaceResource.getEntryType()); assertSame(EntryType.IN, interfaceResource.getEntryType());


// As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments()); // As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());


+ 2
- 3
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistryTest.java View File

@@ -18,9 +18,8 @@ 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 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.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcResult;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;


@@ -41,7 +40,7 @@ public class DubboFallbackRegistryTest {
public void testCustomFallback() { public void testCustomFallback() {
BlockException ex = new FlowException("xxx"); BlockException ex = new FlowException("xxx");
DubboFallbackRegistry.setConsumerFallback( DubboFallbackRegistry.setConsumerFallback(
(invoker, invocation, e) -> new RpcResult("Error: " + e.getClass().getName()));
(invoker, invocation, e) -> AsyncRpcResult.newDefaultAsyncResult("Error: " + e.getClass().getName(), invocation));
Result result = DubboFallbackRegistry.getConsumerFallback() Result result = DubboFallbackRegistry.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());


+ 1
- 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoService.java View File

@@ -20,4 +20,5 @@ package com.alibaba.csp.sentinel.adapter.dubbo.provider;
*/ */
public interface DemoService { public interface DemoService {
String sayHello(String name, int n); String sayHello(String name, int n);
String sayHi(String name,int n);
} }

+ 5
- 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/impl/DemoServiceImpl.java View File

@@ -24,4 +24,9 @@ public class DemoServiceImpl implements DemoService {
public String sayHello(String name, int n) { public String sayHello(String name, int n) {
return "Hello " + name + ", " + n; return "Hello " + name + ", " + n;
} }

@Override
public String sayHi(String name, int n) {
return "Hi " + name + ", " + n;
}
} }

+ 1
- 1
sentinel-demo/sentinel-demo-apache-dubbo/pom.xml View File

@@ -15,7 +15,7 @@
<dependency> <dependency>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId> <artifactId>dubbo</artifactId>
<version>2.7.1</version>
<version>2.7.3</version>
</dependency> </dependency>


<!-- Dubbo provides qos plugin and is enable by default. --> <!-- Dubbo provides qos plugin and is enable by default. -->


+ 108
- 2
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooConsumerBootstrap.java View File

@@ -15,12 +15,22 @@
*/ */
package com.alibaba.csp.sentinel.demo.apache.dubbo; package com.alibaba.csp.sentinel.demo.apache.dubbo;


import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.ConsumerConfiguration; import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.ConsumerConfiguration;
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.FooServiceConsumer; import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.FooServiceConsumer;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;

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.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/** /**
* Please add the following VM arguments: * Please add the following VM arguments:
* <pre> * <pre>
@@ -33,10 +43,14 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
*/ */
public class FooConsumerBootstrap { public class FooConsumerBootstrap {


public static void main(String[] args) {
private static final String INTERFACE_RES_KEY = FooService.class.getName();
private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)";

public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
consumerContext.register(ConsumerConfiguration.class); consumerContext.register(ConsumerConfiguration.class);
consumerContext.refresh(); consumerContext.refresh();
initFlowRule(10, false);


FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class); FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);


@@ -50,5 +64,97 @@ public class FooConsumerBootstrap {
ex.printStackTrace(); ex.printStackTrace();
} }
} }

// method flowcontrol
Thread.sleep(1000);
initFlowRule(20, true);
for (int i = 0; i < 10; i++) {
try {
String message = service.sayHello("Eric");
System.out.println("Success: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
System.out.println("fallback:" + service.doAnother());

} catch (Exception ex) {
ex.printStackTrace();
}
}

// fallback to result
Thread.sleep(1000);
registryCustomFallback();

for (int i = 0; i < 10; i++) {
try {
String message = service.sayHello("Eric");
System.out.println("Result: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}
// fallback to exception
Thread.sleep(1000);
registryCustomFallbackForCustomException();

for (int i = 0; i < 10; i++) {
try {
String message = service.sayHello("Eric");
System.out.println("Result: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}

Thread.sleep(1000);
registryCustomFallbackWhenFallbackError();
for (int i = 0; i < 10; i++) {
try {
String message = service.sayHello("Eric");
System.out.println("Result: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

public static void registryCustomFallback() {
DubboFallbackRegistry.setConsumerFallback(
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult("fallback", invocation));

}

public static void registryCustomFallbackForCustomException() {
DubboFallbackRegistry.setConsumerFallback(
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult(new RuntimeException("fallback"), invocation));
}

public static void registryCustomFallbackWhenFallbackError() {
DubboFallbackRegistry.setConsumerFallback(
(invoker, invocation, ex) -> {
throw new RuntimeException("fallback");
});
}


private static void initFlowRule(int interfaceFlowLimit, boolean method) {
FlowRule flowRule = new FlowRule(INTERFACE_RES_KEY)
.setCount(interfaceFlowLimit)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
List<FlowRule> list = new ArrayList<>();
if (method) {
FlowRule flowRule1 = new FlowRule(RES_KEY)
.setCount(5)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
list.add(flowRule1);
}
list.add(flowRule);
FlowRuleManager.loadRules(list);
} }
} }

+ 119
- 0
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooConsumerExceptionDegradeBootstrap.java View File

@@ -0,0 +1,119 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.demo.apache.dubbo;

import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry;
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.ConsumerConfiguration;
import com.alibaba.csp.sentinel.demo.apache.dubbo.consumer.FooServiceConsumer;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
* Please add the following VM arguments:
* <pre>
* -Djava.net.preferIPv4Stack=true
* -Dcsp.sentinel.api.port=8721
* -Dproject.name=dubbo-consumer-demo
* </pre>
*
* @author Zechao zheng
*/
public class FooConsumerExceptionDegradeBootstrap {

private static final String INTERFACE_RES_KEY = FooService.class.getName();
private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)";

public static void main(String[] args) throws InterruptedException, ExecutionException {
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
consumerContext.register(ConsumerConfiguration.class);
consumerContext.refresh();

FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class);
initExceptionFallback(3);
registryCustomFallback();
for (int i = 0; i < 10; i++) {
try {
String message = service.exceptionTest(true, false);
System.out.println("Result: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}
// sleep 3s to skip the time window
initExceptionFallback(3);
Thread.sleep(3000);
for (int i = 0; i < 10; i++) {
try {
String message = service.exceptionTest(false, true);
System.out.println("Result: " + message);
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}

initExceptionFallback(3);
Thread.sleep(3000);

try {
// timeout to trigger the fallback
CompletableFuture<String> completableFuture = RpcContext.getContext().asyncCall(() -> service.exceptionTest(false, true));
System.out.println("Result: " + completableFuture.get());
} catch (Exception e) {
e.printStackTrace();
}

for (int i = 0; i < 10; i++) {
try {
CompletableFuture<String> result = RpcContext.getContext().asyncCall(() -> service.exceptionTest(false, true));
System.out.println("Result: " + result.get());
} catch (SentinelRpcException ex) {
System.out.println("Blocked");
} catch (Exception ex) {
ex.printStackTrace();
}
}

}

public static void registryCustomFallback() {
DubboFallbackRegistry.setConsumerFallback(
(invoker, invocation, ex) -> AsyncRpcResult.newDefaultAsyncResult("fallback", invocation));

}

public static void initExceptionFallback(int timewindow) {
DegradeRule degradeRule = new DegradeRule(INTERFACE_RES_KEY)
.setCount(0.5)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
.setTimeWindow(timewindow)
.setMinRequestAmount(1);
DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));

}
}

+ 0
- 10
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooProviderBootstrap.java View File

@@ -37,15 +37,11 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
*/ */
public class FooProviderBootstrap { public class FooProviderBootstrap {


private static final String INTERFACE_RES_KEY = FooService.class.getName();
private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)";

public static void main(String[] args) { public static void main(String[] args) {
// Users don't need to manually call this method. // Users don't need to manually call this method.
// Only for eager initialization. // Only for eager initialization.
InitExecutor.doInit(); InitExecutor.doInit();


initFlowRule();


AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ProviderConfiguration.class); context.register(ProviderConfiguration.class);
@@ -54,10 +50,4 @@ public class FooProviderBootstrap {
System.out.println("Service provider is ready"); System.out.println("Service provider is ready");
} }


private static void initFlowRule() {
FlowRule flowRule = new FlowRule(INTERFACE_RES_KEY)
.setCount(10)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
}
} }

+ 2
- 0
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooService.java View File

@@ -23,4 +23,6 @@ public interface FooService {
String sayHello(String name); String sayHello(String name);


String doAnother(); String doAnother();

String exceptionTest(boolean biz, boolean timeout);
} }

+ 5
- 2
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/FooServiceConsumer.java View File

@@ -16,7 +16,6 @@
package com.alibaba.csp.sentinel.demo.apache.dubbo.consumer; package com.alibaba.csp.sentinel.demo.apache.dubbo.consumer;


import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService; import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService;

import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Reference;


/** /**
@@ -24,7 +23,7 @@ import org.apache.dubbo.config.annotation.Reference;
*/ */
public class FooServiceConsumer { public class FooServiceConsumer {


@Reference(url = "dubbo://127.0.0.1:25758", timeout = 3000)
@Reference(url = "dubbo://127.0.0.1:25758", timeout = 500)
private FooService fooService; private FooService fooService;


public String sayHello(String name) { public String sayHello(String name) {
@@ -34,4 +33,8 @@ public class FooServiceConsumer {
public String doAnother() { public String doAnother() {
return fooService.doAnother(); return fooService.doAnother();
} }

public String exceptionTest(boolean biz, boolean timeout) {
return fooService.exceptionTest(biz, timeout);
}
} }

+ 18
- 3
sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/FooServiceImpl.java View File

@@ -15,12 +15,11 @@
*/ */
package com.alibaba.csp.sentinel.demo.apache.dubbo.provider; package com.alibaba.csp.sentinel.demo.apache.dubbo.provider;


import java.time.LocalDateTime;

import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService; import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService;

import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.config.annotation.Service;


import java.time.LocalDateTime;

/** /**
* @author Eric Zhao * @author Eric Zhao
*/ */
@@ -36,4 +35,20 @@ public class FooServiceImpl implements FooService {
public String doAnother() { public String doAnother() {
return LocalDateTime.now().toString(); return LocalDateTime.now().toString();
} }

@Override
public String exceptionTest(boolean biz, boolean timeout) {
if (biz) {
throw new RuntimeException("biz exception");
}
if (timeout) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Success";
}

} }

Loading…
Cancel
Save