Hystrix не закорачивает - PullRequest
       9

Hystrix не закорачивает

0 голосов
/ 27 декабря 2018

Я пытаюсь настроить поведение 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)));
    }

}

Я ожидаю, что произойдет короткое замыкание входящих команд после того, как только одно исключение (или тайм-аут) произойдет в течение следующих 10secs (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 () возвращает false в исключении testSimpleUnsuccessfulExecutionBecauseException и testSimpleUnsuccessfulExecutionBec.1009 *

Может ли кто-нибудь вести меня по правильному пути?Спасибо.

1 Ответ

0 голосов
/ 02 января 2019

Были некоторые ошибки в этих тестах, вот исправленная версия.

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

    }

}
...