【问题标题】:Test drive Hystrix Circuit Breaker configuration试驾 Hystrix 断路器配置
【发布时间】:2016-12-11 09:45:38
【问题描述】:

我们的应用程序是通过使用 Hystrix 实现断路器模式以防脆弱的方式编写的。

整个应用程序是使用测试驱动实践创建的,但卡在了我们需要通过在方法上配置相同的方法来实现断路器策略的地方。

以下是我们使用的示例配置 -

@HystrixCommand(commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "8"),
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "25"),
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")},
        fallbackMethod = "retrieveMapFallback")

如果有可用的功能或机会在我的集成测试中测试驱动它(加载整个 WebApplicationContext,因此知道应用程序可用的所有配置),任何人都可以发表评论吗?

或者,如果这根本不可能在我的应用上下文中得到验证?

任何输入都是有价值的。

【问题讨论】:

    标签: tdd spring-test hystrix spring-cloud-netflix circuit-breaker


    【解决方案1】:

    您可以测试您的Hystrix 断路器配置。

    例如,看看这个带有Spring Boot 1.4的示例应用程序:

    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.stereotype.Component;
    
    @EnableCircuitBreaker
    @SpringBootApplication
    public class HystrixDemo {
    
        public static void main(String[] args) {
            SpringApplication.run(HystrixDemo.class, args);
        }
    
        @Component
        static class MyService {
    
            static final String COMMAND_KEY = "MyCommandKey";
    
            private final Outbound outbound;
    
            MyService(Outbound outbound) {
                this.outbound = outbound;
            }
    
            @HystrixCommand(
                    commandKey = COMMAND_KEY,
                    commandProperties = {
                        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2016")
                    })
            void process() {
                outbound.call();
            }
        }
    
        interface Outbound {
            void call();
        }
    }
    

    您的配置测试可能如下所示:

    import com.netflix.hystrix.HystrixCommandKey;
    import com.netflix.hystrix.HystrixCommandMetrics;
    import com.netflix.hystrix.HystrixCommandProperties;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import static org.junit.Assert.assertTrue;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyServiceCircuitBreakerConfigurationTests {
    
        @Autowired
        private HystrixDemo.MyService myService;
    
        @MockBean
        private HystrixDemo.Outbound outbound;
    
        @Before
        public void setup() {
            warmUpCircuitBreaker();
        }
    
        @Test
        public void shouldHaveCustomTimeout() {
            assertTrue(getCircuitBreakerCommandProperties().executionTimeoutInMilliseconds().get() == 2016);
        }
    
        private void warmUpCircuitBreaker() {
            myService.process();
        }
    
        public static HystrixCommandProperties getCircuitBreakerCommandProperties() {
            return HystrixCommandMetrics.getInstance(getCommandKey()).getProperties();
        }
    
        private static HystrixCommandKey getCommandKey() {
            return HystrixCommandKey.Factory.asKey(HystrixDemo.MyService.COMMAND_KEY);
        }
    }
    

    另外,如果你想测试断路器,你可以看看这个测试:

    import com.netflix.config.ConfigurationManager;
    import com.netflix.hystrix.Hystrix;
    import com.netflix.hystrix.HystrixCircuitBreaker;
    import com.netflix.hystrix.HystrixCommandKey;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertTrue;
    import static org.junit.Assert.fail;
    import static org.mockito.BDDMockito.willThrow;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyServiceCircuitBreakerTests {
    
        @Autowired
        private HystrixDemo.MyService myService;
    
        @MockBean
        private HystrixDemo.Outbound outbound;
    
        @Before
        public void setup() {
            resetHystrix();
            warmUpCircuitBreaker();
            openCircuitBreakerAfterOneFailingRequest();
        }
    
        @Test
        public void shouldTripCircuit() throws InterruptedException {
            willThrow(new RuntimeException()).given(outbound).call();
    
            HystrixCircuitBreaker circuitBreaker = getCircuitBreaker();
    
            // demonstrates circuit is actually closed
            assertFalse(circuitBreaker.isOpen());
            assertTrue(circuitBreaker.allowRequest());
    
            try {
                myService.process();
                fail("unexpected");
            } catch (RuntimeException exception) {
                waitUntilCircuitBreakerOpens();
                assertTrue(circuitBreaker.isOpen());
                assertFalse(circuitBreaker.allowRequest());
            }
        }
    
        private void waitUntilCircuitBreakerOpens() throws InterruptedException {
            /* one second is almost sufficient
               borrowed from https://github.com/Netflix/Hystrix/blob/v1.5.5/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java#L140
             */
            Thread.sleep(1000);
        }
    
        private void resetHystrix() {
            Hystrix.reset();
        }
    
        private void warmUpCircuitBreaker() {
            myService.process();
        }
    
        public static HystrixCircuitBreaker getCircuitBreaker() {
            return HystrixCircuitBreaker.Factory.getInstance(getCommandKey());
        }
    
        private static HystrixCommandKey getCommandKey() {
            return HystrixCommandKey.Factory.asKey(HystrixDemo.MyService.COMMAND_KEY);
        }
    
        private void openCircuitBreakerAfterOneFailingRequest() {
            ConfigurationManager.getConfigInstance().setProperty("hystrix.command." + HystrixDemo.MyService.COMMAND_KEY + ".circuitBreaker.requestVolumeThreshold", 1);
        }
    }   
    

    【讨论】:

    • 这是一个很好的答案。谢谢@ksokol。如果有任何意见,我会尝试并分享。
    猜你喜欢
    • 2015-06-19
    • 2019-06-03
    • 2018-07-09
    • 2020-10-29
    • 2016-08-06
    • 2018-10-05
    • 2019-06-27
    • 2015-12-06
    • 2016-01-11
    相关资源
    最近更新 更多