- Update test cases and demo Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -19,10 +19,10 @@ import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.SphU; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.log.RecordLog; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||
import com.alibaba.dubbo.common.extension.Activate; | |||
import com.alibaba.dubbo.rpc.Filter; | |||
import com.alibaba.dubbo.rpc.Invocation; | |||
@@ -39,6 +39,7 @@ import com.alibaba.dubbo.rpc.RpcException; | |||
* </pre> | |||
* | |||
* @author leyou | |||
* @author Eric Zhao | |||
*/ | |||
@Activate(group = "consumer") | |||
public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter { | |||
@@ -58,7 +59,7 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements | |||
methodEntry = SphU.entry(resourceName, EntryType.OUT); | |||
return invoker.invoke(invocation); | |||
} catch (BlockException e) { | |||
throw new SentinelRpcException(e); | |||
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); | |||
} catch (RpcException e) { | |||
Tracer.trace(e); | |||
throw e; | |||
@@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.SphU; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.log.RecordLog; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
@@ -39,6 +40,7 @@ import com.alibaba.dubbo.rpc.RpcException; | |||
* </pre> | |||
* | |||
* @author leyou | |||
* @author Eric Zhao | |||
*/ | |||
@Activate(group = "provider") | |||
public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter { | |||
@@ -63,7 +65,7 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements | |||
return invoker.invoke(invocation); | |||
} catch (BlockException e) { | |||
throw new SentinelRpcException(e); | |||
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); | |||
} catch (RpcException e) { | |||
Tracer.trace(e); | |||
throw e; | |||
@@ -0,0 +1,34 @@ | |||
/* | |||
* 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.fallback; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||
import com.alibaba.dubbo.rpc.Invocation; | |||
import com.alibaba.dubbo.rpc.Invoker; | |||
import com.alibaba.dubbo.rpc.Result; | |||
/** | |||
* @author Eric Zhao | |||
*/ | |||
public class DefaultDubboFallback implements DubboFallback { | |||
@Override | |||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) { | |||
// Just wrap and throw the exception. | |||
throw new SentinelRpcException(ex); | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* 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.fallback; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
import com.alibaba.dubbo.rpc.Invocation; | |||
import com.alibaba.dubbo.rpc.Invoker; | |||
import com.alibaba.dubbo.rpc.Result; | |||
/** | |||
* Fallback handler for Dubbo services. | |||
* | |||
* @author Eric Zhao | |||
*/ | |||
public interface DubboFallback { | |||
/** | |||
* Handle the block exception and provide fallback result. | |||
* | |||
* @param invoker Dubbo invoker | |||
* @param invocation Dubbo invocation | |||
* @param ex block exception | |||
* @return fallback result | |||
*/ | |||
Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex); | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.fallback; | |||
/** | |||
* Global fallback registry for Dubbo. | |||
* | |||
* Note: Degrading is mainly designed for consumer. The provider should not | |||
* give fallback result in most circumstances. | |||
* | |||
* @author Eric Zhao | |||
*/ | |||
public final class DubboFallbackRegistry { | |||
private static volatile DubboFallback consumerFallback = new DefaultDubboFallback(); | |||
private static volatile DubboFallback providerFallback = new DefaultDubboFallback(); | |||
public static DubboFallback getConsumerFallback() { | |||
return consumerFallback; | |||
} | |||
public static void setConsumerFallback(DubboFallback consumerFallback) { | |||
DubboFallbackRegistry.consumerFallback = consumerFallback; | |||
} | |||
public static DubboFallback getProviderFallback() { | |||
return providerFallback; | |||
} | |||
public static void setProviderFallback(DubboFallback providerFallback) { | |||
DubboFallbackRegistry.providerFallback = providerFallback; | |||
} | |||
private DubboFallbackRegistry() {} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* 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.fallback; | |||
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.dubbo.rpc.Invocation; | |||
import com.alibaba.dubbo.rpc.Invoker; | |||
import com.alibaba.dubbo.rpc.Result; | |||
import com.alibaba.dubbo.rpc.RpcResult; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
/** | |||
* @author Eric Zhao | |||
*/ | |||
public class DubboFallbackRegistryTest { | |||
@Test(expected = SentinelRpcException.class) | |||
public void testDefaultFallback() { | |||
// Test for default. | |||
BlockException ex = new FlowException("xxx"); | |||
DubboFallbackRegistry.getConsumerFallback() | |||
.handle(null, null, ex); | |||
} | |||
@Test | |||
public void testCustomFallback() { | |||
BlockException ex = new FlowException("xxx"); | |||
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { | |||
@Override | |||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException e) { | |||
return new RpcResult("Error: " + e.getClass().getName()); | |||
} | |||
}); | |||
Result result = DubboFallbackRegistry.getConsumerFallback() | |||
.handle(null, null, ex); | |||
Assert.assertFalse("The invocation should not fail", result.hasException()); | |||
Assert.assertEquals("Error: " + ex.getClass().getName(), result.getValue()); | |||
} | |||
} |
@@ -15,10 +15,8 @@ | |||
*/ | |||
package com.alibaba.csp.sentinel.demo.dubbo.demo1; | |||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | |||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | |||
import com.alibaba.csp.sentinel.init.InitExecutor; | |||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |||
@@ -36,8 +34,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext | |||
public class FooConsumerBootstrap { | |||
public static void main(String[] args) { | |||
InitExecutor.doInit(); | |||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | |||
consumerContext.register(ConsumerConfiguration.class); | |||
consumerContext.refresh(); | |||
@@ -45,14 +41,14 @@ public class FooConsumerBootstrap { | |||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class); | |||
for (int i = 0; i < 15; i++) { | |||
try { | |||
String message = service.sayHello("Eric"); | |||
System.out.println("Success: " + message); | |||
} catch (SentinelRpcException ex) { | |||
System.out.println("Blocked"); | |||
} catch (Exception ex) { | |||
ex.printStackTrace(); | |||
} | |||
try { | |||
String message = service.sayHello("Eric"); | |||
System.out.println("Success: " + message); | |||
} catch (SentinelRpcException ex) { | |||
System.out.println("Blocked"); | |||
} catch (Exception ex) { | |||
ex.printStackTrace(); | |||
} | |||
} | |||
} | |||
} |
@@ -40,9 +40,11 @@ public class FooProviderBootstrap { | |||
private static final String INTERFACE_RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService"; | |||
public static void main(String[] args) { | |||
initFlowRule(); | |||
// Users don't need to manually call this method. | |||
InitExecutor.doInit(); | |||
initFlowRule(); | |||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | |||
context.register(ProviderConfiguration.class); | |||
context.refresh(); | |||
@@ -19,6 +19,7 @@ import java.util.Collections; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory; | |||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | |||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | |||
@@ -27,6 +28,8 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; | |||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | |||
import com.alibaba.dubbo.rpc.Result; | |||
import com.alibaba.dubbo.rpc.RpcResult; | |||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |||
@@ -50,7 +53,6 @@ public class FooConsumerBootstrap { | |||
public static void main(String[] args) { | |||
initFlowRule(); | |||
InitExecutor.doInit(); | |||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | |||
consumerContext.register(ConsumerConfiguration.class); | |||
@@ -68,9 +70,7 @@ public class FooConsumerBootstrap { | |||
ex.printStackTrace(); | |||
} | |||
}); | |||
pool.submit(() -> { | |||
System.out.println("Another: " + service.doAnother()); | |||
}); | |||
pool.submit(() -> System.out.println("Another: " + service.doAnother())); | |||
} | |||
} | |||
@@ -82,4 +82,12 @@ public class FooConsumerBootstrap { | |||
flowRule.setLimitApp("default"); | |||
FlowRuleManager.loadRules(Collections.singletonList(flowRule)); | |||
} | |||
private static void registerFallback() { | |||
// Register fallback handler for consumer. | |||
// If you only want to handle degrading, you need to | |||
// check the type of BlockException. | |||
DubboFallbackRegistry.setConsumerFallback((a, b, ex) -> | |||
new RpcResult("Error: " + ex.getClass().getTypeName())); | |||
} | |||
} |
@@ -32,6 +32,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext | |||
public class FooProviderBootstrap { | |||
public static void main(String[] args) { | |||
// Users don't need to manually call this method. | |||
InitExecutor.doInit(); | |||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | |||