Feign超时时间设置


吉星23526

于 2021-10-20 13:37:37 发布

10960
 收藏 11
文章标签: javascript http java
版权
Feign超时时间设置
起因
feign参数配置
发现了两个问题
问题一排查
首先看入口类FeignAutoConfiguration
配置文件对应类FeignClientProperties
FeignClientFactoryBean类用于读取配置参数来进行feign配置
问题二排查
LoadBalancerFeignClient
SpringClientFactory
起因
最近想通过配置feign参数,来改变feign客户端之间connectTimeout和readTimeout。

feign参数配置
feign:
  client:
    config:
      default:
        #不设置connectTimeout会导致readTimeout设置不生效
        connectTimeout: 3000
        readTimeout: 6000 
1
2
3
4
5
6
7
发现了两个问题
1 只设置单独的connectTimeout或者readTimeout时不生效,必须两个值都设置才行
2 发现feign默认的connectTimeout时长是10s,readTimeout时长是60s。但是实际服务之间调用readTimeout超过1秒就会超时。

问题一排查
首先看入口类FeignAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
        FeignHttpClientProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {
1
2
3
4
5
6
配置文件对应类FeignClientProperties
@ConfigurationProperties("feign.client")
public class FeignClientProperties {
1
2
排查发现feign是通过FeignClientProperties来接收配置文件中的配置的。

FeignClientFactoryBean类用于读取配置参数来进行feign配置
protected void configureUsingProperties(
            FeignClientProperties.FeignClientConfiguration config,
            Feign.Builder builder) {
        if (config == null) {
            return;
        }

        if (config.getLoggerLevel() != null) {
            builder.logLevel(config.getLoggerLevel());
        }

        if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
            builder.options(new Request.Options(config.getConnectTimeout(),
                    config.getReadTimeout()));
        }

        if (config.getRetryer() != null) {
            Retryer retryer = getOrInstantiate(config.getRetryer());
            builder.retryer(retryer);
        }

        if (config.getErrorDecoder() != null) {
            ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
            builder.errorDecoder(errorDecoder);
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
跟踪configureUsingProperties方法最终发现了问题一产生的原因。

问题二排查
基于问题一中configureUsingProperties方法去跟踪Request.Options的默认值发现如下

   /**
     * Creates the new Options instance using the following defaults:
     * <ul>
     * <li>Connect Timeout: 10 seconds</li>
     * <li>Read Timeout: 60 seconds</li>
     * <li>Follow all 3xx redirects</li>
     * </ul>
     */
    public Options() {
      this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
    }
    /**
     * Creates a new Options instance.
     *
     * @param connectTimeoutMillis connection timeout in milliseconds.
     * @param readTimeoutMillis read timeout in milliseconds.
     * @param followRedirects if the request should follow 3xx redirections.
     *
     * @deprecated please use {@link #Options(long, TimeUnit, long, TimeUnit, boolean)}
     */
    @Deprecated
    public Options(int connectTimeoutMillis, int readTimeoutMillis, boolean followRedirects) {
      this(connectTimeoutMillis, TimeUnit.MILLISECONDS,
          readTimeoutMillis, TimeUnit.MILLISECONDS,
          followRedirects);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
其默认的connectTimeout时长是10s,readTimeout时长是60s。很奇怪为啥我的项目1秒就超时呢??

LoadBalancerFeignClient
该类用于处理feign客户端的http请求,跟断点进来的。具体咋找到这这里我也记不清了,总之很曲折。

@Override
    public Response execute(Request request, Request.Options options) throws IOException {
        try {
            URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
                    this.delegate, request, uriWithoutHost);

            IClientConfig requestConfig = getClientConfig(options, clientName);
            return lbClient(clientName)
                    .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
        }
        catch (ClientException e) {
            IOException io = findIOException(e);
            if (io != null) {
                throw io;
            }
            throw new RuntimeException(e);
        }
    }
//获取feign的方法继续跟这里到【this.clientFactory.getClientConfig】    
IClientConfig getClientConfig(Request.Options options, String clientName) {
        IClientConfig requestConfig;
        if (options == DEFAULT_OPTIONS) {
            requestConfig = this.clientFactory.getClientConfig(clientName);
        }
        else {
            requestConfig = new FeignOptionsClientConfig(options);
        }
        return requestConfig;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
可以看到当options没有被修改过时,feign的配置信息会通过clientFactory(SpringClientFactory)获取。这里可以自己打个断点,可以看到clientFactory.getClientConfig(xxx)返回的配置信息中connectTimeout和readTimeout都只有1秒,到此feign的两个问题已经找到了答案。

SpringClientFactory
延申下clientFactory对象其实就是SpringClientFactory,该类作用:创建客户端、负载均衡器和客户端配置实例的工厂。 它为每个客户端名称创建一个 Spring ApplicationContext,并从那里提取它需要的 bean。个人理解就是每个feign客户端在服务端中都有一个独立的子容器。这块还有待学习。

/**
     * Get the client config associated with the name.
     * @param name name to search by
     * @return {@link IClientConfig} instance
     * @throws RuntimeException if any error occurs
     */
    public IClientConfig getClientConfig(String name) {
        return getInstance(name, IClientConfig.class);
    }
————————————————
版权声明:本文为CSDN博主「吉星23526」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011523825/article/details/120819416

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值