前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(3)

SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(3)

作者头像
干货满满张哈希
发布2021-12-30 16:02:05
4220
发布2021-12-30 16:02:05
举报
文章被收录于专栏:干货满满张哈希

本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent

我们继续上一节针对我们的重试进行测试

验证针对可重试的方法响应超时异常重试正确

我们可以通过 httpbin.org 的 /delay/响应时间秒 来实现请求响应超时。例如 /delay/3 就会延迟三秒后返回。这个接口也是可以接受任何类型的 HTTP 请求方法。

我们先来指定关于 Feign 超时的配置 Options:

代码语言:javascript
复制
//SpringExtension也包含了 Mockito 相关的 Extension,所以 @Mock 等注解也生效了
@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = {
        //关闭 eureka client
        "eureka.client.enabled=false",
        //默认请求重试次数为 3
        "resilience4j.retry.configs.default.maxAttempts=3",
        //指定默认响应超时为 2s
        "feign.client.config.default.readTimeout=2000",
})
@Log4j2
public class OpenFeignClientTest {
    @SpringBootApplication
    @Configuration
    public static class App {
        @Bean
        public DiscoveryClient discoveryClient() {
            //模拟两个服务实例
            ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class);
            ServiceInstance service1Instance3 = Mockito.spy(ServiceInstance.class);
            Map<String, String> zone1 = Map.ofEntries(
                    Map.entry("zone", "zone1")
            );
            when(service1Instance1.getMetadata()).thenReturn(zone1);
            when(service1Instance1.getInstanceId()).thenReturn("service1Instance1");
            when(service1Instance1.getHost()).thenReturn("httpbin.org");
            when(service1Instance1.getPort()).thenReturn(80);
            DiscoveryClient spy = Mockito.spy(DiscoveryClient.class);
            //微服务 testService1 有一个实例即 service1Instance1
            Mockito.when(spy.getInstances("testService1"))
                    .thenReturn(List.of(service1Instance1));
            return spy;
        }
    }
}

我们分别定义会超时和不会超时的接口:

代码语言:javascript
复制
@FeignClient(name = "testService1", contextId = "testService1Client")
public interface TestService1Client {
    @GetMapping("/delay/1")
    String testGetDelayOneSecond();

    @GetMapping("/delay/3")
    String testGetDelayThreeSeconds();
}

编写测试,还是通过获取调用负载均衡获取实例的次数确定请求调用了多少次。

代码语言:javascript
复制
@Test
public void testTimeOutAndRetry() throws InterruptedException {
    Span span = tracer.nextSpan();
    try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) {
        //防止断路器影响
        circuitBreakerRegistry.getAllCircuitBreakers().asJava().forEach(CircuitBreaker::reset);
        long l = span.context().traceId();
        RoundRobinWithRequestSeparatedPositionLoadBalancer loadBalancerClientFactoryInstance
                = (RoundRobinWithRequestSeparatedPositionLoadBalancer) loadBalancerClientFactory.getInstance("testService1");
        AtomicInteger atomicInteger = loadBalancerClientFactoryInstance.getPositionCache().get(l);
        int start = atomicInteger.get();
        //不超时,则不会有重试,也不会有异常导致 fallback
        String s = testService1Client.testGetDelayOneSecond();
        //没有重试,只会请求一次
        Assertions.assertEquals(1, atomicInteger.get() - start);

        //防止断路器影响
        circuitBreakerRegistry.getAllCircuitBreakers().asJava().forEach(CircuitBreaker::reset);
        start = atomicInteger.get();
        //超时,并且方法可以重试,所以会请求 3 次
        try {
            s = testService1Client.testGetDelayThreeSeconds();
        } catch(Exception e) {}
        Assertions.assertEquals(3, atomicInteger.get() - start);
    }
}

验证针对不可重试的方法响应超时异常不能重试

对于 GET 方法,我们默认是可以重试的。但是一般扣款这种涉及修改请求的接口,我们会使用其他方法例如 POST。这一类方法一般请求超时我们不会直接重试的。我们还是通过 httporg.bin 的延迟接口进行测试:

代码语言:javascript
复制
@FeignClient(name = "testService1", contextId = "testService1Client")
public interface TestService1Client {
    @PostMapping("/delay/3")
    String testPostDelayThreeSeconds();
}

编写测试,还是通过获取调用负载均衡获取实例的次数确定请求调用了多少次。

代码语言:javascript
复制
@Test
public void testTimeOutAndRetry() throws InterruptedException {
    Span span = tracer.nextSpan();
    try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) {
        //防止断路器影响
        circuitBreakerRegistry.getAllCircuitBreakers().asJava().forEach(CircuitBreaker::reset);
        long l = span.context().traceId();
        RoundRobinWithRequestSeparatedPositionLoadBalancer loadBalancerClientFactoryInstance
                = (RoundRobinWithRequestSeparatedPositionLoadBalancer) loadBalancerClientFactory.getInstance("testService1");
        AtomicInteger atomicInteger = loadBalancerClientFactoryInstance.getPositionCache().get(l);
        int start = atomicInteger.get();
        //不超时,则不会有重试,也不会有异常导致 fallback
        String s = testService1Client.testPostDelayThreeSeconds();
        //没有重试,只会请求一次
        Assertions.assertEquals(1, atomicInteger.get() - start);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 验证针对可重试的方法响应超时异常重试正确
  • 验证针对不可重试的方法响应超时异常不能重试
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的四七层流量分发服务,访问流量经由 CLB 可以自动分配到多台后端服务器上,扩展系统的服务能力并消除单点故障。轻松应对大流量访问场景。 网关负载均衡(Gateway Load Balancer,GWLB)是运行在网络层的负载均衡。通过 GWLB 可以帮助客户部署、扩展和管理第三方虚拟设备,操作简单,安全性强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档