- 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.EntryType; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | 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.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 com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||||
import com.alibaba.dubbo.common.extension.Activate; | import com.alibaba.dubbo.common.extension.Activate; | ||||
import com.alibaba.dubbo.rpc.Filter; | import com.alibaba.dubbo.rpc.Filter; | ||||
import com.alibaba.dubbo.rpc.Invocation; | import com.alibaba.dubbo.rpc.Invocation; | ||||
@@ -39,6 +39,7 @@ import com.alibaba.dubbo.rpc.RpcException; | |||||
* </pre> | * </pre> | ||||
* | * | ||||
* @author leyou | * @author leyou | ||||
* @author Eric Zhao | |||||
*/ | */ | ||||
@Activate(group = "consumer") | @Activate(group = "consumer") | ||||
public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter { | public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter { | ||||
@@ -58,7 +59,7 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements | |||||
methodEntry = SphU.entry(resourceName, EntryType.OUT); | methodEntry = SphU.entry(resourceName, EntryType.OUT); | ||||
return invoker.invoke(invocation); | return invoker.invoke(invocation); | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
throw new SentinelRpcException(e); | |||||
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); | |||||
} catch (RpcException e) { | } catch (RpcException e) { | ||||
Tracer.trace(e); | Tracer.trace(e); | ||||
throw e; | throw e; | ||||
@@ -19,6 +19,7 @@ import com.alibaba.csp.sentinel.Entry; | |||||
import com.alibaba.csp.sentinel.EntryType; | import com.alibaba.csp.sentinel.EntryType; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | 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.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; | ||||
@@ -39,6 +40,7 @@ import com.alibaba.dubbo.rpc.RpcException; | |||||
* </pre> | * </pre> | ||||
* | * | ||||
* @author leyou | * @author leyou | ||||
* @author Eric Zhao | |||||
*/ | */ | ||||
@Activate(group = "provider") | @Activate(group = "provider") | ||||
public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter { | public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter { | ||||
@@ -63,7 +65,7 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements | |||||
return invoker.invoke(invocation); | return invoker.invoke(invocation); | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
throw new SentinelRpcException(e); | |||||
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); | |||||
} catch (RpcException e) { | } catch (RpcException e) { | ||||
Tracer.trace(e); | Tracer.trace(e); | ||||
throw 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; | 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.ConsumerConfiguration; | ||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | 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 com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | ||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||||
@@ -36,8 +34,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext | |||||
public class FooConsumerBootstrap { | public class FooConsumerBootstrap { | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
InitExecutor.doInit(); | |||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | ||||
consumerContext.register(ConsumerConfiguration.class); | consumerContext.register(ConsumerConfiguration.class); | ||||
consumerContext.refresh(); | consumerContext.refresh(); | ||||
@@ -45,14 +41,14 @@ public class FooConsumerBootstrap { | |||||
FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class); | FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class); | ||||
for (int i = 0; i < 15; i++) { | 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"; | private static final String INTERFACE_RES_KEY = "com.alibaba.csp.sentinel.demo.dubbo.FooService"; | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
initFlowRule(); | |||||
// Users don't need to manually call this method. | |||||
InitExecutor.doInit(); | InitExecutor.doInit(); | ||||
initFlowRule(); | |||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | ||||
context.register(ProviderConfiguration.class); | context.register(ProviderConfiguration.class); | ||||
context.refresh(); | context.refresh(); | ||||
@@ -19,6 +19,7 @@ import java.util.Collections; | |||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | 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.concurrent.NamedThreadFactory; | ||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | ||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | 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.SentinelRpcException; | ||||
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 com.alibaba.dubbo.rpc.Result; | |||||
import com.alibaba.dubbo.rpc.RpcResult; | |||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||||
@@ -50,7 +53,6 @@ public class FooConsumerBootstrap { | |||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
initFlowRule(); | initFlowRule(); | ||||
InitExecutor.doInit(); | |||||
AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); | ||||
consumerContext.register(ConsumerConfiguration.class); | consumerContext.register(ConsumerConfiguration.class); | ||||
@@ -68,9 +70,7 @@ public class FooConsumerBootstrap { | |||||
ex.printStackTrace(); | 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"); | flowRule.setLimitApp("default"); | ||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule)); | 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 class FooProviderBootstrap { | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
// Users don't need to manually call this method. | |||||
InitExecutor.doInit(); | InitExecutor.doInit(); | ||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); | ||||