Configure readtimeout for okhttp (#669)

This commit is contained in:
Olga Maciaszek-Sharma
2022-01-14 20:02:06 +01:00
committed by GitHub
parent 8b1c1dbf4c
commit d626518dc5
7 changed files with 87 additions and 28 deletions

View File

@@ -26,6 +26,7 @@
|feign.httpclient.hc5.socket-timeout-unit | | Default value for socket timeout unit.
|feign.httpclient.max-connections | `200` |
|feign.httpclient.max-connections-per-route | `50` |
|feign.httpclient.ok-http-client-properties.read-timeout | `60s` | {@link OkHttpClient} read timeout; defaults to 60 seconds.
|feign.httpclient.time-to-live | `900` |
|feign.httpclient.time-to-live-unit | |
|feign.metrics.enabled | `true` | Enables metrics capability for Feign.

View File

@@ -739,7 +739,7 @@ To work around this problem you can use an `ObjectProvider` when autowiring your
[source,java,indent=0]
----
@Autowired
ObjectProvider<TestFeginClient> testFeginClient;
ObjectProvider<TestFeignClient> testFeignClient;
----
=== Spring Data Support

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.openfeign;
import java.io.IOException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
@@ -274,8 +275,8 @@ public class FeignAutoConfiguration {
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
int maxTotalConnections = httpClientProperties.getMaxConnections();
long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@@ -283,12 +284,13 @@ public class FeignAutoConfiguration {
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
boolean followRedirects = httpClientProperties.isFollowRedirects();
int connectTimeout = httpClientProperties.getConnectionTimeout();
boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
Duration readTimeout = httpClientProperties.getOkHttpClientProperties().getReadTimeout();
this.okHttpClient = httpClientFactory.createBuilder(disableSslValidation)
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects)
.connectionPool(connectionPool).build();
.readTimeout(readTimeout).connectionPool(connectionPool).build();
return this.okHttpClient;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.openfeign.clientconfig;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
@@ -48,8 +49,8 @@ public class OkHttpFeignConfiguration {
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
int maxTotalConnections = httpClientProperties.getMaxConnections();
long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@@ -57,11 +58,12 @@ public class OkHttpFeignConfiguration {
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
boolean followRedirects = httpClientProperties.isFollowRedirects();
int connectTimeout = httpClientProperties.getConnectionTimeout();
Duration reaTimeout = httpClientProperties.getOkHttpClientProperties().getReadTimeout();
this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects)
.connectionPool(connectionPool).build();
.readTimeout(reaTimeout).connectionPool(connectionPool).build();
return this.okHttpClient;
}

View File

@@ -16,13 +16,17 @@
package org.springframework.cloud.openfeign.support;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import feign.okhttp.OkHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Ryan Baxter
* @author Nguyen Ky Thanh
* @author Olga Maciaszek-Sharma
*/
@ConfigurationProperties(prefix = "feign.httpclient")
public class FeignHttpClientProperties {
@@ -88,8 +92,13 @@ public class FeignHttpClientProperties {
*/
private Hc5Properties hc5 = new Hc5Properties();
/**
* Additional {@link OkHttpClient}-specific properties.
*/
private OkHttpClientProperties okHttpClientProperties = new OkHttpClientProperties();
public int getConnectionTimerRepeat() {
return this.connectionTimerRepeat;
return connectionTimerRepeat;
}
public void setConnectionTimerRepeat(int connectionTimerRepeat) {
@@ -97,7 +106,7 @@ public class FeignHttpClientProperties {
}
public boolean isDisableSslValidation() {
return this.disableSslValidation;
return disableSslValidation;
}
public void setDisableSslValidation(boolean disableSslValidation) {
@@ -105,7 +114,7 @@ public class FeignHttpClientProperties {
}
public int getMaxConnections() {
return this.maxConnections;
return maxConnections;
}
public void setMaxConnections(int maxConnections) {
@@ -113,7 +122,7 @@ public class FeignHttpClientProperties {
}
public int getMaxConnectionsPerRoute() {
return this.maxConnectionsPerRoute;
return maxConnectionsPerRoute;
}
public void setMaxConnectionsPerRoute(int maxConnectionsPerRoute) {
@@ -121,7 +130,7 @@ public class FeignHttpClientProperties {
}
public long getTimeToLive() {
return this.timeToLive;
return timeToLive;
}
public void setTimeToLive(long timeToLive) {
@@ -129,7 +138,7 @@ public class FeignHttpClientProperties {
}
public TimeUnit getTimeToLiveUnit() {
return this.timeToLiveUnit;
return timeToLiveUnit;
}
public void setTimeToLiveUnit(TimeUnit timeToLiveUnit) {
@@ -137,7 +146,7 @@ public class FeignHttpClientProperties {
}
public boolean isFollowRedirects() {
return this.followRedirects;
return followRedirects;
}
public void setFollowRedirects(boolean followRedirects) {
@@ -145,7 +154,7 @@ public class FeignHttpClientProperties {
}
public int getConnectionTimeout() {
return this.connectionTimeout;
return connectionTimeout;
}
public void setConnectionTimeout(int connectionTimeout) {
@@ -160,6 +169,14 @@ public class FeignHttpClientProperties {
this.hc5 = hc5;
}
public OkHttpClientProperties getOkHttpClientProperties() {
return okHttpClientProperties;
}
public void setOkHttpClientProperties(OkHttpClientProperties okHttpClientProperties) {
this.okHttpClientProperties = okHttpClientProperties;
}
public static class Hc5Properties {
/**
@@ -203,7 +220,7 @@ public class FeignHttpClientProperties {
private TimeUnit socketTimeoutUnit = DEFAULT_SOCKET_TIMEOUT_UNIT;
public PoolConcurrencyPolicy getPoolConcurrencyPolicy() {
return this.poolConcurrencyPolicy;
return poolConcurrencyPolicy;
}
public void setPoolConcurrencyPolicy(PoolConcurrencyPolicy poolConcurrencyPolicy) {
@@ -272,4 +289,24 @@ public class FeignHttpClientProperties {
}
/**
* {@link OkHttpClient}-specific properties.
*/
public static class OkHttpClientProperties {
/**
* {@link OkHttpClient} read timeout; defaults to 60 seconds.
*/
private Duration readTimeout = Duration.ofSeconds(60);
public Duration getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
}

View File

@@ -45,26 +45,33 @@ class FeignOkHttpConfigurationTests {
void setUp() {
this.context = new SpringApplicationBuilder()
.properties("debug=true", "feign.httpclient.disableSslValidation=true", "feign.okhttp.enabled=true",
"feign.httpclient.enabled=false")
"feign.httpclient.enabled=false", "feign.httpclient.okhttp-client-properties.read-timeout=9s")
.web(WebApplicationType.NONE).sources(HttpClientConfiguration.class, FeignAutoConfiguration.class)
.run();
}
@AfterEach
void tearDown() {
if (this.context != null) {
this.context.close();
if (context != null) {
context.close();
}
}
@Test
void disableSslTest() {
OkHttpClient httpClient = this.context.getBean(OkHttpClient.class);
OkHttpClient httpClient = context.getBean(OkHttpClient.class);
HostnameVerifier hostnameVerifier = (HostnameVerifier) this.getField(httpClient, "hostnameVerifier");
assertThat(hostnameVerifier instanceof OkHttpClientFactory.TrustAllHostnames).isTrue();
}
protected <T> Object getField(Object target, String name) {
@Test
void shouldConfigureReadTimeout() {
OkHttpClient httpClient = context.getBean(OkHttpClient.class);
assertThat(httpClient.readTimeoutMillis()).isEqualTo(9000);
}
protected Object getField(Object target, String name) {
Field field = ReflectionUtils.findField(target.getClass(), name);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);

View File

@@ -33,6 +33,7 @@ import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfigurati
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.util.ReflectionTestUtils.getField;
/**
* @author Olga Maciaszek-Sharma
@@ -58,9 +59,18 @@ class FeignLoadBalancerAutoConfigurationTests {
@Test
void shouldInstantiateOkHttpFeignClientWhenEnabled() {
ConfigurableApplicationContext context = initContext("feign.httpclient.enabled=false",
"feign.okhttp.enabled=true", "spring.cloud.loadbalancer.retry.enabled=false");
"feign.okhttp.enabled=true", "spring.cloud.loadbalancer.retry.enabled=false",
"feign.httpclient.okhttp-client-properties.read-timeout=9s");
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
assertLoadBalanced(context, OkHttpClient.class);
Map<String, FeignBlockingLoadBalancerClient> beans = context
.getBeansOfType(FeignBlockingLoadBalancerClient.class);
assertThat(beans).as("Missing bean of type %s", OkHttpClient.class).hasSize(1);
Client client = beans.get("feignClient").getDelegate();
assertThat(client).isInstanceOf(OkHttpClient.class);
OkHttpClient okHttpClient = (OkHttpClient) client;
okhttp3.OkHttpClient httpClient = (okhttp3.OkHttpClient) getField(okHttpClient, "delegate");
assertThat(httpClient.readTimeoutMillis()).isEqualTo(9000);
}
@Test