feign默认的连接时长10s和读取时长60s不生效

默认时长不生效问题

    • 前言
      • 组件版本
      • 具体内容
      • 问题描述
    • 解决过程
      • 通过写死ip地址(域名也可)实现,示例
      • 通过从 eureka 获取 ip地址,示例
      • 这两个方法的入口地址
      • 造成实现不同的原因
    • 总结

前言

组件版本

springcloud  =>   Finchley.SR2版本
spring-cloud-starter-openfeign    => 2.0.2.RELEASE
spring-cloud-starter-netflix-eureka-client   =>      2.0.2.RELEASE


具体内容

我这里feign是通过从eureka注册中心获取对应服务的ip地址,然后执行远程服务调用

问题描述

通过方面的方法执行调用时,由于远程服务执行的逻辑较多(处理时长大约2-4s),导致调用者报错,异常信息为
Read timed out executing GET http://FEIGN-INTERFACE/feign/linkByEureka
但是我本地debug的时候,由于偷懒,没有走eureka注册中心,而是直接写了ip地址。然后看它底层实现的时候,发现它的默认值是
字段介绍参考
connectTimeoutMills=10000 //建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用时间
readTimeoutMills=60000 // 指的是建立连接后从服务器读取到可用资源所需的时间,即发送请求到接收到结果的时间
且在这种情况下,我执行调用时为出现前面的错误(我本地模拟的话是直接线程睡眠3s)。
这进一步让我感到困惑,之后我想到有情况对默认值的覆盖情况,但是我测试的仍是写死ip地址,导致迟迟没发现问题。
之后我在查询资料,看到了这里的超时介绍
想到了是否是其他框架对它的实现造成了影响,最后发现是eureka的问题。

解决过程

通过写死ip地址(域名也可)实现,示例

@FeignClient(name = "test",url = "http://localhost:8088")
public interface TestFeign {

    @RequestMapping("/get")
    String get();
}

这种情况下它执行调用的时候是Client.Default.execute(request,options)方法
feign默认的连接时长10s和读取时长60s不生效_第1张图片

通过从 eureka 获取 ip地址,示例

@FeignClient(name = "FEIGN-INTERFACE")
public interface FeignTest {

    @RequestMapping("/feign/linkByEureka")
    String linkByEureka();
}

这种情况下它执行的是LoadBalancerFeignClient.execute(request,options)方法
feign默认的连接时长10s和读取时长60s不生效_第2张图片

这两个方法的入口地址

入口地址为 SynchronousMethodHandler.executeAndDecode(template),源码第88行。

造成实现不同的原因

org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget()方法 源码239行

 T getTarget() {
	FeignContext context = applicationContext.getBean(FeignContext.class);
	Feign.Builder builder = feign(context);
  // 通过注册中心这里进去
	if (!StringUtils.hasText(this.url)) {
		String url;
		if (!this.name.startsWith("http")) {
			url = "http://" + this.name;
		}
		else {
			url = this.name;
		}
		url += cleanPath();
		return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
				this.name, url));
	}
	if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
		this.url = "http://" + this.url;
	}
	// 直接写死ip地址,则跳过前面两个if,这里开始执行逻辑
	String url = this.url + cleanPath();
	Client client = getOptional(context, Client.class); //这个方法两者都会调用,最终获得一个LoadBalancerFeignClient
	if (client != null) {
	// 这里会将 LoadBalancerFeignClient 变回  Client.Default类,从而导致之后采用不同的实现。
		if (client instanceof LoadBalancerFeignClient) {
			// not load balancing because we have a url,
			// but ribbon is on the classpath, so unwrap
			client = ((LoadBalancerFeignClient)client).getDelegate();
		}
		builder.client(client);
	}
	Targeter targeter = get(context, Targeter.class);
	return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
			this.type, this.name, url));
}

总结

// 使用feign 最好 定义超时时间
feign.client.config.default.connect-timeout=2000  // 默认连接超时时间
feign.client.config.default.read-timeout=3000  // 默认读取超时时间
feign.client.config.FEIGN-INTERFACE.connect-timeout=2000  // 某个feign 的时间,用的name字段,区分大小写。
feign.client.config.FEIGN-INTERFACE.read-timeout=3000 // 某个feign 的时间,用的name字段,区分大小写。

2.0.2.RELEASE 版本好像还有个bug,两个时间要同时指定,不然无效。

你可能感兴趣的:(奇奇怪怪的问题,java,eureka,spring,cloud,java,feign,readTimeout)