Refactor and refine implementation of default circuit breaker rule
* Rename: DefaultDegradeSlot -> DefaultCircuitBreakerSlot * Refine DefaultCircuitBreakerRuleManager * Add test cases Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
8b43caede4
commit
19418e71ad
|
|
@ -80,6 +80,7 @@ public final class Constants {
|
||||||
public static final int ORDER_AUTHORITY_SLOT = -6000;
|
public static final int ORDER_AUTHORITY_SLOT = -6000;
|
||||||
public static final int ORDER_SYSTEM_SLOT = -5000;
|
public static final int ORDER_SYSTEM_SLOT = -5000;
|
||||||
public static final int ORDER_FLOW_SLOT = -2000;
|
public static final int ORDER_FLOW_SLOT = -2000;
|
||||||
|
public static final int ORDER_DEFAULT_CIRCUIT_BREAKER_SLOT = -1500;
|
||||||
public static final int ORDER_DEGRADE_SLOT = -1000;
|
public static final int ORDER_DEGRADE_SLOT = -1000;
|
||||||
|
|
||||||
private Constants() {}
|
private Constants() {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1999-2022 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.slots.block.degrade;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty;
|
||||||
|
import com.alibaba.csp.sentinel.property.PropertyListener;
|
||||||
|
import com.alibaba.csp.sentinel.property.SentinelProperty;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ExceptionCircuitBreaker;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ResponseTimeCircuitBreaker;
|
||||||
|
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rule manager for universal default circuit breaker rule.
|
||||||
|
*
|
||||||
|
* @author wuwen
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public final class DefaultCircuitBreakerRuleManager {
|
||||||
|
|
||||||
|
public static final String DEFAULT_KEY = "*";
|
||||||
|
|
||||||
|
private static volatile Map<String, List<CircuitBreaker>> circuitBreakers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static volatile Set<DegradeRule> rules = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resources in this set will not be affected by default rules.
|
||||||
|
*/
|
||||||
|
private static final Set<String> excludedResource = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
private static final DefaultCircuitBreakerRuleManager.RulePropertyListener LISTENER
|
||||||
|
= new DefaultCircuitBreakerRuleManager.RulePropertyListener();
|
||||||
|
private static SentinelProperty<List<DegradeRule>> currentProperty = new DynamicSentinelProperty<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
currentProperty.addListener(LISTENER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to the {@link SentinelProperty} for default circuit breaker rules.
|
||||||
|
*
|
||||||
|
* @param property the property to listen.
|
||||||
|
*/
|
||||||
|
public static void register2Property(SentinelProperty<List<DegradeRule>> property) {
|
||||||
|
AssertUtil.notNull(property, "property cannot be null");
|
||||||
|
synchronized (LISTENER) {
|
||||||
|
RecordLog.info("Registering new property to DefaultCircuitBreakerRuleManager");
|
||||||
|
currentProperty.removeListener(LISTENER);
|
||||||
|
property.addListener(LISTENER);
|
||||||
|
currentProperty = property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<CircuitBreaker> getDefaultCircuitBreakers(String resourceName) {
|
||||||
|
if (rules == null || rules.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<CircuitBreaker> circuitBreakers = DefaultCircuitBreakerRuleManager.circuitBreakers.get(resourceName);
|
||||||
|
if (circuitBreakers == null && !rules.isEmpty() && !excludedResource.contains(resourceName)) {
|
||||||
|
circuitBreakers = new ArrayList<>();
|
||||||
|
for (DegradeRule rule : rules) {
|
||||||
|
circuitBreakers.add(DefaultCircuitBreakerRuleManager.newCircuitBreakerFrom(rule));
|
||||||
|
}
|
||||||
|
DefaultCircuitBreakerRuleManager.circuitBreakers.put(resourceName, circuitBreakers);
|
||||||
|
return circuitBreakers;
|
||||||
|
}
|
||||||
|
return circuitBreakers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclude the resource that does not require default rules.
|
||||||
|
*
|
||||||
|
* @param resourceName the name of resource that does not require default rules
|
||||||
|
*/
|
||||||
|
public static void addExcludedResource(String resourceName) {
|
||||||
|
if (StringUtil.isEmpty(resourceName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
excludedResource.add(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeExcludedResource(String resourceName) {
|
||||||
|
if (StringUtil.isEmpty(resourceName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
excludedResource.remove(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearExcludedResource() {
|
||||||
|
excludedResource.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load default circuit breaker rules, former rules will be replaced.
|
||||||
|
*
|
||||||
|
* @param rules new rules to load.
|
||||||
|
*/
|
||||||
|
public static boolean loadRules(List<DegradeRule> rules) {
|
||||||
|
try {
|
||||||
|
return currentProperty.updateValue(rules);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
RecordLog.error("[DefaultCircuitBreakerRuleManager] Unexpected error when loading default rules", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidDefaultRule(DegradeRule rule) {
|
||||||
|
if (!DegradeRuleManager.isValidRule(rule)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return rule.getResource().equals(DEFAULT_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a circuit breaker instance from provided circuit breaking rule.
|
||||||
|
*
|
||||||
|
* @param rule a valid circuit breaking rule
|
||||||
|
* @return new circuit breaker based on provided rule; null if rule is invalid or unsupported type
|
||||||
|
*/
|
||||||
|
private static CircuitBreaker newCircuitBreakerFrom(/*@Valid*/ DegradeRule rule) {
|
||||||
|
switch (rule.getGrade()) {
|
||||||
|
case RuleConstant.DEGRADE_GRADE_RT:
|
||||||
|
return new ResponseTimeCircuitBreaker(rule);
|
||||||
|
case RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO:
|
||||||
|
case RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT:
|
||||||
|
return new ExceptionCircuitBreaker(rule);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CircuitBreaker getExistingSameCbOrNew(/*@Valid*/ DegradeRule rule) {
|
||||||
|
List<CircuitBreaker> cbs = getCircuitBreakers(rule.getResource());
|
||||||
|
if (cbs == null || cbs.isEmpty()) {
|
||||||
|
return newCircuitBreakerFrom(rule);
|
||||||
|
}
|
||||||
|
for (CircuitBreaker cb : cbs) {
|
||||||
|
if (rule.equals(cb.getRule())) {
|
||||||
|
// Reuse the circuit breaker if the rule remains unchanged.
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newCircuitBreakerFrom(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<CircuitBreaker> getCircuitBreakers(String resourceName) {
|
||||||
|
return circuitBreakers.get(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RulePropertyListener implements PropertyListener<List<DegradeRule>> {
|
||||||
|
|
||||||
|
private synchronized void reloadFrom(List<DegradeRule> list) {
|
||||||
|
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
// clearing all rules
|
||||||
|
DefaultCircuitBreakerRuleManager.circuitBreakers = new ConcurrentHashMap<>();
|
||||||
|
DefaultCircuitBreakerRuleManager.rules = new HashSet<>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<DegradeRule> rules = new HashSet<DegradeRule>();
|
||||||
|
for (DegradeRule rule : list) {
|
||||||
|
if (!isValidDefaultRule(rule)) {
|
||||||
|
RecordLog.warn(
|
||||||
|
"[DefaultCircuitBreakerRuleManager] Ignoring invalid rule when loading new rules: {}", rule);
|
||||||
|
} else {
|
||||||
|
if (StringUtil.isBlank(rule.getLimitApp())) {
|
||||||
|
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
|
||||||
|
}
|
||||||
|
// TODO: Set a special ID for default circuit breaker rule (so that it could be identified)
|
||||||
|
|
||||||
|
rules.add(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<CircuitBreaker>> cbMap = new ConcurrentHashMap<String, List<CircuitBreaker>>(8);
|
||||||
|
for (String resourceNameKey : DefaultCircuitBreakerRuleManager.circuitBreakers.keySet()) {
|
||||||
|
List<CircuitBreaker> cbs = new ArrayList<CircuitBreaker>();
|
||||||
|
for (DegradeRule rule : rules) {
|
||||||
|
CircuitBreaker cb = getExistingSameCbOrNew(rule);
|
||||||
|
cbs.add(cb);
|
||||||
|
}
|
||||||
|
cbMap.put(resourceNameKey, cbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultCircuitBreakerRuleManager.rules = rules;
|
||||||
|
DefaultCircuitBreakerRuleManager.circuitBreakers = cbMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configUpdate(List<DegradeRule> conf) {
|
||||||
|
reloadFrom(conf);
|
||||||
|
RecordLog.info("[DefaultCircuitBreakerRuleManager] Default circuit breaker rules has been updated to: {}",
|
||||||
|
rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configLoad(List<DegradeRule> conf) {
|
||||||
|
reloadFrom(conf);
|
||||||
|
RecordLog.info("[DefaultCircuitBreakerRuleManager] Default circuit breaker rules loaded: {}", rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1999-2022 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.slots.block.degrade;
|
package com.alibaba.csp.sentinel.slots.block.degrade;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.Constants;
|
import com.alibaba.csp.sentinel.Constants;
|
||||||
|
|
@ -5,6 +20,7 @@ import com.alibaba.csp.sentinel.Entry;
|
||||||
import com.alibaba.csp.sentinel.context.Context;
|
import com.alibaba.csp.sentinel.context.Context;
|
||||||
import com.alibaba.csp.sentinel.node.DefaultNode;
|
import com.alibaba.csp.sentinel.node.DefaultNode;
|
||||||
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
|
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
|
||||||
|
import com.alibaba.csp.sentinel.slotchain.ProcessorSlot;
|
||||||
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.BlockException;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
||||||
|
|
@ -13,10 +29,13 @@ import com.alibaba.csp.sentinel.spi.Spi;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* <p>A {@link ProcessorSlot} dedicates to universal default circuit breaker.</p>
|
||||||
|
*
|
||||||
* @author wuwen
|
* @author wuwen
|
||||||
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Spi(order = Constants.ORDER_DEGRADE_SLOT + 100)
|
@Spi(order = Constants.ORDER_DEFAULT_CIRCUIT_BREAKER_SLOT)
|
||||||
public class DefaultDegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
|
public class DefaultCircuitBreakerSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
|
||||||
|
|
@ -27,12 +46,12 @@ public class DefaultDegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode>
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performChecking(Context context, ResourceWrapper r) throws BlockException {
|
private void performChecking(Context context, ResourceWrapper r) throws BlockException {
|
||||||
|
// If user has set a degrade rule for the resource, the default rule will not be activated
|
||||||
if (DegradeRuleManager.hasConfig(r.getName())) {
|
if (DegradeRuleManager.hasConfig(r.getName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CircuitBreaker> circuitBreakers = DefaultDegradeRuleManager.getDefaultCircuitBreakers(r.getName());
|
List<CircuitBreaker> circuitBreakers = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(r.getName());
|
||||||
|
|
||||||
if (circuitBreakers == null || circuitBreakers.isEmpty()) {
|
if (circuitBreakers == null || circuitBreakers.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -58,9 +77,10 @@ public class DefaultDegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CircuitBreaker> circuitBreakers = DefaultDegradeRuleManager.getDefaultCircuitBreakers(r.getName());
|
List<CircuitBreaker> circuitBreakers = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(r.getName());
|
||||||
|
|
||||||
if (circuitBreakers == null || circuitBreakers.isEmpty()) {
|
if (circuitBreakers == null || circuitBreakers.isEmpty()) {
|
||||||
|
fireExit(context, r, count, args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
package com.alibaba.csp.sentinel.slots.block.degrade;
|
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
|
||||||
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty;
|
|
||||||
import com.alibaba.csp.sentinel.property.PropertyListener;
|
|
||||||
import com.alibaba.csp.sentinel.property.SentinelProperty;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ExceptionCircuitBreaker;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ResponseTimeCircuitBreaker;
|
|
||||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author wuwen
|
|
||||||
*/
|
|
||||||
public class DefaultDegradeRuleManager {
|
|
||||||
|
|
||||||
public static final String DEFAULT_KEY = "*";
|
|
||||||
|
|
||||||
private static volatile Map<String, List<CircuitBreaker>> circuitBreakers = new ConcurrentHashMap<>();
|
|
||||||
private static volatile Set<DegradeRule> rules = new HashSet<>();
|
|
||||||
|
|
||||||
private static final DefaultDegradeRuleManager.RulePropertyListener LISTENER = new DefaultDegradeRuleManager.RulePropertyListener();
|
|
||||||
private static SentinelProperty<List<DegradeRule>> currentProperty
|
|
||||||
= new DynamicSentinelProperty<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
currentProperty.addListener(LISTENER);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static List<CircuitBreaker> getDefaultCircuitBreakers(String resourceName) {
|
|
||||||
List<CircuitBreaker> circuitBreakers = DefaultDegradeRuleManager.circuitBreakers.get(resourceName);
|
|
||||||
if (circuitBreakers == null && !rules.isEmpty()) {
|
|
||||||
return DefaultDegradeRuleManager.circuitBreakers.computeIfAbsent(resourceName,
|
|
||||||
r -> rules.stream().map(DefaultDegradeRuleManager::newCircuitBreakerFrom).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
return circuitBreakers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load {@link DegradeRule}s, former rules will be replaced.
|
|
||||||
*
|
|
||||||
* @param rules new rules to load.
|
|
||||||
*/
|
|
||||||
public static void loadRules(List<DegradeRule> rules) {
|
|
||||||
try {
|
|
||||||
currentProperty.updateValue(rules);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
RecordLog.error("[DefaultDegradeRuleManager] Unexpected error when loading degrade rules", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isValidDefaultRule(DegradeRule rule) {
|
|
||||||
if (!DegradeRuleManager.isValidRule(rule)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rule.getResource().equals(DEFAULT_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a circuit breaker instance from provided circuit breaking rule.
|
|
||||||
*
|
|
||||||
* @param rule a valid circuit breaking rule
|
|
||||||
* @return new circuit breaker based on provided rule; null if rule is invalid or unsupported type
|
|
||||||
*/
|
|
||||||
private static CircuitBreaker newCircuitBreakerFrom(/*@Valid*/ DegradeRule rule) {
|
|
||||||
switch (rule.getGrade()) {
|
|
||||||
case RuleConstant.DEGRADE_GRADE_RT:
|
|
||||||
return new ResponseTimeCircuitBreaker(rule);
|
|
||||||
case RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO:
|
|
||||||
case RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT:
|
|
||||||
return new ExceptionCircuitBreaker(rule);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class RulePropertyListener implements PropertyListener<List<DegradeRule>> {
|
|
||||||
|
|
||||||
private synchronized void reloadFrom(List<DegradeRule> list) {
|
|
||||||
|
|
||||||
if (list == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<DegradeRule> rules = new HashSet<>();
|
|
||||||
List<CircuitBreaker> cbs = new ArrayList<>();
|
|
||||||
|
|
||||||
for (DegradeRule rule : list) {
|
|
||||||
if (!isValidDefaultRule(rule)) {
|
|
||||||
RecordLog.warn("[DefaultDegradeRuleManager] Ignoring invalid rule when loading new rules: {}", rule);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (StringUtil.isBlank(rule.getLimitApp())) {
|
|
||||||
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
|
|
||||||
}
|
|
||||||
CircuitBreaker cb = newCircuitBreakerFrom(rule);
|
|
||||||
cbs.add(cb);
|
|
||||||
rules.add(rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, List<CircuitBreaker>> cbMap = new ConcurrentHashMap<>(8);
|
|
||||||
|
|
||||||
DefaultDegradeRuleManager.circuitBreakers.forEach((k, v) -> cbMap.put(k, cbs));
|
|
||||||
|
|
||||||
DefaultDegradeRuleManager.rules = rules;
|
|
||||||
DefaultDegradeRuleManager.circuitBreakers = cbMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configUpdate(List<DegradeRule> conf) {
|
|
||||||
reloadFrom(conf);
|
|
||||||
RecordLog.info("[DefaultDegradeRuleManager] Degrade rules has been updated to: {}", rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configLoad(List<DegradeRule> conf) {
|
|
||||||
reloadFrom(conf);
|
|
||||||
RecordLog.info("[DefaultDegradeRuleManager] Degrade rules loaded: {}", rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,4 +7,4 @@ com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot
|
||||||
com.alibaba.csp.sentinel.slots.system.SystemSlot
|
com.alibaba.csp.sentinel.slots.system.SystemSlot
|
||||||
com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
|
com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
|
||||||
com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot
|
com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot
|
||||||
com.alibaba.csp.sentinel.slots.block.degrade.DefaultDegradeSlot
|
com.alibaba.csp.sentinel.slots.block.degrade.DefaultCircuitBreakerSlot
|
||||||
|
|
@ -18,7 +18,7 @@ package com.alibaba.csp.sentinel.slots;
|
||||||
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
|
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
|
||||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain;
|
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain;
|
||||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot;
|
import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DefaultDegradeSlot;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DefaultCircuitBreakerSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot;
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
|
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
|
||||||
|
|
@ -69,10 +69,10 @@ public class DefaultSlotChainBuilderTest {
|
||||||
assertTrue(next instanceof FlowSlot);
|
assertTrue(next instanceof FlowSlot);
|
||||||
|
|
||||||
next = next.getNext();
|
next = next.getNext();
|
||||||
assertTrue(next instanceof DegradeSlot);
|
assertTrue(next instanceof DefaultCircuitBreakerSlot);
|
||||||
|
|
||||||
next = next.getNext();
|
next = next.getNext();
|
||||||
assertTrue(next instanceof DefaultDegradeSlot);
|
assertTrue(next instanceof DegradeSlot);
|
||||||
|
|
||||||
next = next.getNext();
|
next = next.getNext();
|
||||||
assertNull(next);
|
assertNull(next);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ public class CircuitBreakingIntegrationTest extends AbstractTimeBasedTest {
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
DegradeRuleManager.loadRules(new ArrayList<>());
|
DegradeRuleManager.loadRules(new ArrayList<>());
|
||||||
DefaultDegradeRuleManager.loadRules(new ArrayList<>());
|
DefaultCircuitBreakerRuleManager.loadRules(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -126,8 +126,8 @@ public class CircuitBreakingIntegrationTest extends AbstractTimeBasedTest {
|
||||||
String res = "CircuitBreakingIntegrationTest_testSlowRequestModeUseDefaultRule";
|
String res = "CircuitBreakingIntegrationTest_testSlowRequestModeUseDefaultRule";
|
||||||
EventObserverRegistry.getInstance().addStateChangeObserver(res, observer);
|
EventObserverRegistry.getInstance().addStateChangeObserver(res, observer);
|
||||||
|
|
||||||
DefaultDegradeRuleManager.loadRules(Arrays.asList(
|
DefaultCircuitBreakerRuleManager.loadRules(Arrays.asList(
|
||||||
new DegradeRule(DefaultDegradeRuleManager.DEFAULT_KEY).setTimeWindow(retryTimeoutSec).setCount(maxRt)
|
new DegradeRule(DefaultCircuitBreakerRuleManager.DEFAULT_KEY).setTimeWindow(retryTimeoutSec).setCount(maxRt)
|
||||||
.setStatIntervalMs(statIntervalMs).setMinRequestAmount(minRequestAmount)
|
.setStatIntervalMs(statIntervalMs).setMinRequestAmount(minRequestAmount)
|
||||||
.setSlowRatioThreshold(0.8d).setGrade(0)));
|
.setSlowRatioThreshold(0.8d).setGrade(0)));
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ public class CircuitBreakingIntegrationTest extends AbstractTimeBasedTest {
|
||||||
// Circuit breaker has transformed to OPEN since here.
|
// Circuit breaker has transformed to OPEN since here.
|
||||||
verify(observer)
|
verify(observer)
|
||||||
.onStateChange(eq(State.CLOSED), eq(State.OPEN), any(DegradeRule.class), anyDouble());
|
.onStateChange(eq(State.CLOSED), eq(State.OPEN), any(DegradeRule.class), anyDouble());
|
||||||
assertEquals(State.OPEN, DefaultDegradeRuleManager.getDefaultCircuitBreakers(res).get(0).currentState());
|
assertEquals(State.OPEN, DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(res).get(0).currentState());
|
||||||
assertFalse(entryAndSleepFor(res, 1));
|
assertFalse(entryAndSleepFor(res, 1));
|
||||||
|
|
||||||
sleepSecond(1);
|
sleepSecond(1);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1999-2022 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.slots.block.degrade;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
*/
|
||||||
|
public class DefaultCircuitBreakerRuleManagerTest {
|
||||||
|
|
||||||
|
private final String RESOURCE_NAME = "method_";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule = new DegradeRule(DefaultCircuitBreakerRuleManager.DEFAULT_KEY)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
.setCount(50)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
assertTrue(DegradeRuleManager.isValidRule(rule));
|
||||||
|
rules.add(rule);
|
||||||
|
DefaultCircuitBreakerRuleManager.loadRules(rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
DefaultCircuitBreakerRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||||
|
DegradeRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsValidRule() {
|
||||||
|
DegradeRule rule1 = new DegradeRule("xx")
|
||||||
|
.setCount(0.1d)
|
||||||
|
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||||
|
.setTimeWindow(2);
|
||||||
|
|
||||||
|
DegradeRule rule2 = new DegradeRule(DefaultCircuitBreakerRuleManager.DEFAULT_KEY)
|
||||||
|
.setCount(0.1d)
|
||||||
|
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||||
|
.setTimeWindow(2);
|
||||||
|
|
||||||
|
assertFalse(DefaultCircuitBreakerRuleManager.isValidDefaultRule(rule1));
|
||||||
|
assertTrue(DefaultCircuitBreakerRuleManager.isValidDefaultRule(rule2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDefaultCircuitBreakers() {
|
||||||
|
String resourceName = RESOURCE_NAME + "I";
|
||||||
|
|
||||||
|
assertFalse(DegradeRuleManager.hasConfig(resourceName));
|
||||||
|
|
||||||
|
List<CircuitBreaker> defaultCircuitBreakers1 = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(
|
||||||
|
resourceName);
|
||||||
|
assertNotNull(defaultCircuitBreakers1);
|
||||||
|
|
||||||
|
List<CircuitBreaker> defaultCircuitBreakers2 = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(
|
||||||
|
resourceName);
|
||||||
|
assertSame(defaultCircuitBreakers1, defaultCircuitBreakers2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDefaultCircuitBreakersWhileAddingCustomizedRule() {
|
||||||
|
String resourceNameI = RESOURCE_NAME + "I";
|
||||||
|
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule = new DegradeRule(resourceNameI)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
.setCount(50)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
rules.add(rule);
|
||||||
|
DegradeRuleManager.loadRules(rules);
|
||||||
|
|
||||||
|
assertTrue(DegradeRuleManager.hasConfig(resourceNameI));
|
||||||
|
|
||||||
|
String resourceNameII = RESOURCE_NAME + "II";
|
||||||
|
List<DegradeRule> rules2 = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule2 = new DegradeRule(resourceNameII)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
.setCount(50)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
rules2.add(rule2);
|
||||||
|
DegradeRuleManager.loadRules(rules2);
|
||||||
|
assertFalse(DegradeRuleManager.hasConfig(resourceNameI));
|
||||||
|
assertNotNull(DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resourceNameI));
|
||||||
|
|
||||||
|
DegradeRuleManager.loadRules(rules);
|
||||||
|
DefaultCircuitBreakerRuleManager.addExcludedResource(resourceNameII);
|
||||||
|
assertFalse(DegradeRuleManager.hasConfig(resourceNameII));
|
||||||
|
assertNull(DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resourceNameII));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDefaultCircuitBreakersWhileRemovingCustomizedRule() {
|
||||||
|
String resourceNameI = RESOURCE_NAME + "I";
|
||||||
|
DefaultCircuitBreakerRuleManager.addExcludedResource(resourceNameI);
|
||||||
|
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule = new DegradeRule(resourceNameI)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
.setCount(50)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
rules.add(rule);
|
||||||
|
DegradeRuleManager.loadRules(rules);
|
||||||
|
|
||||||
|
assertTrue(DegradeRuleManager.hasConfig(resourceNameI));
|
||||||
|
assertNull(DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resourceNameI));
|
||||||
|
|
||||||
|
//remove customized rule and do not recover default rule
|
||||||
|
List<DegradeRule> rules2 = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRuleManager.loadRules(rules2);
|
||||||
|
assertFalse(DegradeRuleManager.hasConfig(resourceNameI));
|
||||||
|
assertNull(DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resourceNameI));
|
||||||
|
|
||||||
|
//recover default rule
|
||||||
|
DefaultCircuitBreakerRuleManager.removeExcludedResource(resourceNameI);
|
||||||
|
assertFalse(DegradeRuleManager.hasConfig(resourceNameI));
|
||||||
|
assertNotNull(DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resourceNameI));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadRules() {
|
||||||
|
DegradeRule rule = mock(DegradeRule.class);
|
||||||
|
List<DegradeRule> ruleList = new ArrayList<DegradeRule>();
|
||||||
|
ruleList.add(rule);
|
||||||
|
assertTrue(DefaultCircuitBreakerRuleManager.loadRules(ruleList));
|
||||||
|
assertFalse(DefaultCircuitBreakerRuleManager.loadRules(ruleList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadRulesUseDifferentCircuitBreakers() throws Exception {
|
||||||
|
String resA = "resA";
|
||||||
|
String resB = "resB";
|
||||||
|
List<CircuitBreaker> cbsForResourceA = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resA);
|
||||||
|
assertNotNull(cbsForResourceA);
|
||||||
|
List<CircuitBreaker> cbsForResourceB = DefaultCircuitBreakerRuleManager.getDefaultCircuitBreakers(resB);
|
||||||
|
assertNotNull(cbsForResourceB);
|
||||||
|
assertNotEquals(cbsForResourceA, cbsForResourceB);
|
||||||
|
Field cbsField;
|
||||||
|
try {
|
||||||
|
cbsField = DefaultCircuitBreakerRuleManager.class.getDeclaredField("circuitBreakers");
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
cbsField.setAccessible(true);
|
||||||
|
Map<String, List<CircuitBreaker>> cbs = (Map<String, List<CircuitBreaker>>) cbsField.get(
|
||||||
|
DefaultCircuitBreakerRuleManager.class);
|
||||||
|
assertEquals(2, cbs.size());
|
||||||
|
|
||||||
|
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule = new DegradeRule(DefaultCircuitBreakerRuleManager.DEFAULT_KEY)
|
||||||
|
//rule is different in strategy
|
||||||
|
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
|
||||||
|
.setCount(0.1d)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
assertTrue(DegradeRuleManager.isValidRule(rule));
|
||||||
|
rules.add(rule);
|
||||||
|
DefaultCircuitBreakerRuleManager.loadRules(rules);
|
||||||
|
try {
|
||||||
|
cbsField = DefaultCircuitBreakerRuleManager.class.getDeclaredField("circuitBreakers");
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
cbsField.setAccessible(true);
|
||||||
|
Map<String, List<CircuitBreaker>> newCbs = (Map<String, List<CircuitBreaker>>) cbsField.get(
|
||||||
|
DefaultCircuitBreakerRuleManager.class);
|
||||||
|
assertEquals(2, newCbs.size());
|
||||||
|
assertNotEquals(cbs, newCbs);
|
||||||
|
|
||||||
|
List<CircuitBreaker> resACbs = newCbs.get(resA);
|
||||||
|
assertNotNull(resACbs);
|
||||||
|
List<CircuitBreaker> resBCbs = newCbs.get(resB);
|
||||||
|
assertNotNull(resBCbs);
|
||||||
|
assertNotEquals(resACbs, resBCbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright 1999-2022 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.slots.block.degrade;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.EntryType;
|
||||||
|
import com.alibaba.csp.sentinel.context.Context;
|
||||||
|
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
|
||||||
|
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
*/
|
||||||
|
public class DefaultCircuitBreakerSlotTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
||||||
|
DegradeRule rule = new DegradeRule(DefaultCircuitBreakerRuleManager.DEFAULT_KEY)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
.setCount(50)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
rules.add(rule);
|
||||||
|
DefaultCircuitBreakerRuleManager.loadRules(rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
DefaultCircuitBreakerRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPerformChecking() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||||
|
DefaultCircuitBreakerSlot defaultCircuitBreakerSlot = mock(DefaultCircuitBreakerSlot.class);
|
||||||
|
Context context = mock(Context.class);
|
||||||
|
String resA = "resA";
|
||||||
|
Method pCMethod = DefaultCircuitBreakerSlot.class.getDeclaredMethod("performChecking", Context.class, ResourceWrapper.class);
|
||||||
|
pCMethod.setAccessible(true);
|
||||||
|
pCMethod.invoke(defaultCircuitBreakerSlot, context, new StringResourceWrapper(resA, EntryType.IN));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ import com.alibaba.csp.sentinel.slotchain.ProcessorSlot;
|
||||||
import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder;
|
import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder;
|
||||||
import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder;
|
import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder;
|
||||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot;
|
import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DefaultDegradeSlot;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DefaultCircuitBreakerSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot;
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
|
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
|
||||||
|
|
@ -30,6 +30,7 @@ import com.alibaba.csp.sentinel.slots.logger.LogSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot;
|
import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot;
|
import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot;
|
||||||
import com.alibaba.csp.sentinel.slots.system.SystemSlot;
|
import com.alibaba.csp.sentinel.slots.system.SystemSlot;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
@ -106,7 +107,7 @@ public class SpiLoaderTest {
|
||||||
singletonSlotClasses.add(SystemSlot.class);
|
singletonSlotClasses.add(SystemSlot.class);
|
||||||
singletonSlotClasses.add(FlowSlot.class);
|
singletonSlotClasses.add(FlowSlot.class);
|
||||||
singletonSlotClasses.add(DegradeSlot.class);
|
singletonSlotClasses.add(DegradeSlot.class);
|
||||||
singletonSlotClasses.add(DefaultDegradeSlot.class);
|
singletonSlotClasses.add(DefaultCircuitBreakerSlot.class);
|
||||||
|
|
||||||
for (int i = 0; i < slots1.size(); i++) {
|
for (int i = 0; i < slots1.size(); i++) {
|
||||||
ProcessorSlot slot1 = slots1.get(i);
|
ProcessorSlot slot1 = slots1.get(i);
|
||||||
|
|
@ -161,8 +162,8 @@ public class SpiLoaderTest {
|
||||||
assertTrue(sortedSlots.get(index++) instanceof AuthoritySlot);
|
assertTrue(sortedSlots.get(index++) instanceof AuthoritySlot);
|
||||||
assertTrue(sortedSlots.get(index++) instanceof SystemSlot);
|
assertTrue(sortedSlots.get(index++) instanceof SystemSlot);
|
||||||
assertTrue(sortedSlots.get(index++) instanceof FlowSlot);
|
assertTrue(sortedSlots.get(index++) instanceof FlowSlot);
|
||||||
|
assertTrue(sortedSlots.get(index++) instanceof DefaultCircuitBreakerSlot);
|
||||||
assertTrue(sortedSlots.get(index++) instanceof DegradeSlot);
|
assertTrue(sortedSlots.get(index++) instanceof DegradeSlot);
|
||||||
assertTrue(sortedSlots.get(index++) instanceof DefaultDegradeSlot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -179,8 +180,8 @@ public class SpiLoaderTest {
|
||||||
ProcessorSlot slot = SpiLoader.of(ProcessorSlot.class).loadLowestPriorityInstance();
|
ProcessorSlot slot = SpiLoader.of(ProcessorSlot.class).loadLowestPriorityInstance();
|
||||||
assertNotNull(slot);
|
assertNotNull(slot);
|
||||||
|
|
||||||
// NodeSelectorSlot is lowest order priority with @Spi(order = -1000) among all slots
|
// DegradeSlot is lowest order priority with @Spi(order = -1000) among all slots
|
||||||
assertTrue(slot instanceof DefaultDegradeSlot);
|
assertTrue(slot instanceof DegradeSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -221,7 +222,8 @@ public class SpiLoaderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadInstanceByAliasName() {
|
public void testLoadInstanceByAliasName() {
|
||||||
ProcessorSlot slot = SpiLoader.of(ProcessorSlot.class).loadInstance("com.alibaba.csp.sentinel.slots.statistic.StatisticSlot");
|
ProcessorSlot slot = SpiLoader.of(ProcessorSlot.class).loadInstance(
|
||||||
|
"com.alibaba.csp.sentinel.slots.statistic.StatisticSlot");
|
||||||
assertNotNull(slot);
|
assertNotNull(slot);
|
||||||
assertTrue(slot instanceof StatisticSlot);
|
assertTrue(slot instanceof StatisticSlot);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue