Add default fallback support for Dubbo
- Update test cases and demo Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
0438d530d4
commit
b37c237a61
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue