【问题标题】:Hystrix is not short-circuitingHystrix 没有短路
【发布时间】:2019-05-25 07:52:35
【问题描述】:

我正在尝试以这种方式设置 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。

有人可以指导我正确的方式吗?谢谢。

【问题讨论】:

    标签: java hystrix


    【解决方案1】:

    这些测试有一些错误,这里是修复的版本。

    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);
            }
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 2017-05-08
      • 2020-04-13
      • 2012-06-21
      • 2017-05-29
      • 2011-11-08
      • 2021-09-26
      相关资源
      最近更新 更多