java - Hystrix 没有短路
问题描述
我正在尝试以这种方式设置 HystrixCommand 的行为:
public abstract class AbstractCircuitBreakerCommand<E> extends HystrixCommand<E> {
protected AbstractCircuitBreakerCommand(final String groupKey, final String commandKey) {
this(groupKey, commandKey, TimeUnit.SECONDS, 10, TimeUnit.SECONDS, 3, TimeUnit.SECONDS, 10, 1);
}
protected AbstractCircuitBreakerCommand(
final String groupKey, final String commandKey,
final TimeUnit metricsWindowTimeUnit, final int metricsWindowTime,
final TimeUnit timeoutTimeUnit, final int timeoutTime,
final TimeUnit windowTimeUnit, final int windowTime,
final int threshold) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
.withMetricsRollingStatisticalWindowInMilliseconds((int) metricsWindowTimeUnit.toMillis(metricsWindowTime))
.withExecutionTimeoutEnabled(true)
.withExecutionTimeoutInMilliseconds((int) timeoutTimeUnit.toMillis(timeoutTime))
.withCircuitBreakerEnabled(true)
.withCircuitBreakerRequestVolumeThreshold(threshold)
.withCircuitBreakerErrorThresholdPercentage(0)
.withCircuitBreakerSleepWindowInMilliseconds((int) windowTimeUnit.toMillis(windowTime))
.withFallbackEnabled(true)));
}
}
我期望的是在接下来的 10 秒(sleepwindowinmilis)仅发生一个异常(或超时)后,将传入的命令短路。
为了测试它,我进行了下一个单元测试。
public class AbstractCircuitBreakerCommandTest {
private final static int ERROR_VALUE = Integer.MIN_VALUE;
private final static String GROUP_KEY = "GROUP_KEY";
private final static String COMMAND_KEY = "COMMAND_KEY";
@Test
public void testSimpleExecution() {
final int expectedValue = 1;
final SimpleCircuitBreakerCommandToTest circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY, COMMAND_KEY, value -> expectedValue);
Assert.assertEquals(expectedValue, (int) circuitBreakerCommand.execute());
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isSuccessfulExecution());
}
@Test
public void testSimpleUnsuccessfulExecutionBecauseException() {
final SimpleCircuitBreakerCommandToTest circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY, COMMAND_KEY, value -> {
throw new Exception("Test");
});
Assert.assertEquals(ERROR_VALUE, (int) circuitBreakerCommand.execute());
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isFailedExecution());
Assert.assertTrue(circuitBreakerCommand.isCircuitBreakerOpen());
}
@Test
public void testSimpleUnsuccessfulExecutionBecauseTimeout() {
final SimpleCircuitBreakerCommandToTest circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY, COMMAND_KEY, value -> {
SleepHelper.sleep(TimeUnit.SECONDS, 4); // The default value is -> 3 seconds.
return 1;
});
Assert.assertEquals(ERROR_VALUE, (int) circuitBreakerCommand.execute());
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isFailedExecution());
Assert.assertTrue(circuitBreakerCommand.isCircuitBreakerOpen());
}
private static abstract class AbstractCircuitBreakerCommandToTest extends AbstractCircuitBreakerCommand<Integer> {
private final Integer value;
private final TestAction testAction;
protected AbstractCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final TestAction testAction) {
this(groupKey, commandKey, 1, testAction);
}
protected AbstractCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final Integer value, final TestAction testAction) {
super(groupKey, commandKey);
this.value = value;
this.testAction = testAction;
}
@Override
protected Integer run() throws Exception {
return this.testAction.run(this.value);
}
@Override
protected Integer getFallback() {
return ERROR_VALUE;
}
@FunctionalInterface
interface TestAction {
Integer run(final Integer integer) throws Exception;
}
}
private static class SimpleCircuitBreakerCommandToTest extends AbstractCircuitBreakerCommandToTest {
protected SimpleCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final TestAction testAction) {
super(groupKey, commandKey, testAction);
}
}
}
但是 isCircuitBreakerOpen() 方法在 testSimpleUnsuccessfulExecutionBecauseException 和 testSimpleUnsuccessfulExecutionBecauseTimeout 测试中返回 false。
有人可以指导我正确的方式吗?谢谢你。
解决方案
这些测试中有一些错误,这是修复的版本。
public class AbstractCircuitBreakerCommandTest {
private final static int WAIT_WORK_DONE_IN_MS = 800;
private final static int ERROR_VALUE = Integer.MIN_VALUE;
private final static String GROUP_KEY = "GROUP_KEY";
private final static String COMMAND_KEY = "COMMAND_KEY";
@Test
public void testSimpleExecution() {
final int expectedValue = 1;
final HystrixCommand circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY + "_0", COMMAND_KEY + "_0", value -> value);
Assert.assertEquals(expectedValue, (int) circuitBreakerCommand.execute());
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isSuccessfulExecution());
}
@Test
public void testSimpleUnsuccessfulExecutionBecauseException() {
final HystrixCommand circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY + "_1", COMMAND_KEY + "_1", value -> {
throw new Exception("Test");
});
Assert.assertEquals(ERROR_VALUE, (int) circuitBreakerCommand.execute());
SleepHelper.sleep(TimeUnit.MILLISECONDS, WAIT_WORK_DONE_IN_MS);
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isFailedExecution());
Assert.assertTrue(circuitBreakerCommand.isCircuitBreakerOpen());
}
@Test
public void testSimpleUnsuccessfulExecutionBecauseTimeout() {
final HystrixCommand circuitBreakerCommand =
new SimpleCircuitBreakerCommandToTest(GROUP_KEY + "_2", COMMAND_KEY + "_2", value -> {
SleepHelper.sleep(TimeUnit.SECONDS, 4); // The default value is -> 3 seconds.
return value;
});
Assert.assertEquals(ERROR_VALUE, (int) circuitBreakerCommand.execute());
SleepHelper.sleep(TimeUnit.MILLISECONDS, WAIT_WORK_DONE_IN_MS);
Assert.assertTrue(circuitBreakerCommand.isExecutionComplete());
Assert.assertTrue(circuitBreakerCommand.isResponseTimedOut());
Assert.assertTrue(circuitBreakerCommand.isCircuitBreakerOpen());
}
private static abstract class AbstractCircuitBreakerCommandToTest extends AbstractCircuitBreakerCommand<Integer> {
private final Integer value;
private final TestAction testAction;
protected AbstractCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final TestAction testAction) {
this(groupKey, commandKey, 1, testAction);
}
protected AbstractCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final Integer value, final TestAction testAction) {
super(groupKey, commandKey);
this.value = value;
this.testAction = testAction;
}
@Override
protected Integer run() throws Exception {
return this.testAction.run(this.value);
}
@Override
protected Integer getFallback() {
return ERROR_VALUE;
}
@FunctionalInterface
interface TestAction {
Integer run(final Integer integer) throws Exception;
}
}
private static class SimpleCircuitBreakerCommandToTest extends AbstractCircuitBreakerCommandToTest {
protected SimpleCircuitBreakerCommandToTest(
final String groupKey, final String commandKey,
final TestAction testAction) {
super(groupKey, commandKey, testAction);
}
}
}
推荐阅读
- javascript - 如何在选项卡更改时为浏览器选项卡标题的位置设置动画
- informatica-cloud - 我可以在表达式中添加 SOQL 查询以使用 informatica 云从 salesforce 获取数据吗
- jquery - For 循环介于两者之间并仅返回一个值
- javascript - React Router:基于哈希的 NavLink
- c - 重新初始化全局指针数组
- sql - 根据 ID 和最近日期连接表格
- javascript - 检查嵌套数组中的每个值是真还是假的更好方法?
- twitter-bootstrap - 容器颜色没有填满整个容器
- c# - EventHandler 作为方法参数
- python - 尝试使用 python 和 openpyxl 在电子表格中查找非空单元格