In my spring-boot (2.4.0) app I have set up a connection pool and the timeout for outgoing HTTP requests (30 seconds):
#Bean
public RequestConfig requestConfig() {
return RequestConfig.custom()
.setConnectionRequestTimeout(30000)
.setConnectTimeout(30000)
.setSocketTimeout(30000)
.build();
}
#Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager,
RequestConfig requestConfig) {
return HttpClientBuilder
.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
}
#Bean
public RestTemplate restTemplate(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
I autowire restTemplate bean in my Gateway classes and use this restTemplate.exchange(...) to perform HTTP requests. The timeout itself works fine and is applied to all outgoing requests.
But for certain URLs I need to set the timeout to 5 seconds.
Is there a way to override generic timeout settings for certain URLs?
I had this very this problem recently and had two versions of RestTemplate, one for "short timeout" and one for "long timeout". See here.
RestTemplate was really designed to be built with pre-configured timeouts and for those timeouts to stay untouched after initialization. If you use Apache HttpClient then yes you can set a RequestConfig per request and that is the proper design in my opinion.
Related
I have spring boot infrastructure with few microservices. They communicating pretty well between each other. One of the microservices have some third party calls, calling some third party services through http.
I have defined my own RestTemplate and in the init() method I am setting connectTimeout and readTimeout.
From the stack traces I see that my rest template is used.
#PostConstruct
public void init() {
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(connectTimeout);
requestFactory.setReadTimeout(readTimeout);
this.restTemplate = new RestTemplate(requestFactory);
}
The problem is that some of the requests are handing for few minutes and no exceptions are thrown. (my timeouts are much less - about 5-10 seconds)
What may be the cause? Any ideas?
Missing the call to setConnectionRequestTimeout(...);
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setConnectTimeout(connectTimeout);
requestFactory.setReadTimeout(readTimeout);
requestFactory.setConnectionRequestTimeout(...);
this.restTemplate = new RestTemplate(requestFactory);
Spring RestTemplate timeout
Once I've created an Apache HttpClient, how do I get the configuration values from it (what used to be HttpParams)?
For example, if I do something like this to create a client:
RequestConfig requestConfig = RequestConfig.custom()
.setCircularRedirectsAllowed(true)
.setAuthenticationEnabled(true)
.setExpectContinueEnabled(true)
.setConnectionRequestTimeout(10000);
.build();
HttpClient client = HttpClientBuilder
.create()
.setConnectionManager(new PoolingHttpClientConnectionManager(createSchemeRegistry()))
.setDefaultRequestConfig(requestConfig)
.build();
How would I get the value of the connection request timeout from the org.apache.http.client.HttpClient instance? other configuration items?
For AbstractHttpClient there was a method getParams (or similar) but that's all gone away in favour of the HttpClient interface. There's an InternalHttpClient instance that's generated along the way but I think that's not exposed.
The reason I'm interested in this is firstly for testing - I want to verify a HTTP Client was configured correctly, the other case is to present that information in a UI when debugging HTTP traffic - think of something like Charles proxy.
I have a scenario where there is an aggregate endpoint to call multiple downstream systems which are RESTful and gives back the consolidated response from all these systems.
I am currently using a rest template that is configured as a singleton bean and injects it to the corresponding services to make the rest call. The RestTemplate is using the default CloseableHttpClient as the HttpClient, which will close the connections once the request is successful.
Would this be a good approach or would it be better if the rest template is configured per service that is calling its RESTful service?
RestTemplate is thread safe. You could use a pooling connection manager:
#Bean
public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager result = new PoolingHttpClientConnectionManager();
result.setMaxTotal(20); // FIXME Consider making this value configurable
return result;
}
#Bean
public RequestConfig requestConfig() {
RequestConfig result = RequestConfig.custom()
// FIXME Consider making these values configurable
.setConnectionRequestTimeout(2000)
.setConnectTimeout(2000)
.setSocketTimeout(2000)
.build();
return result;
}
#Bean
public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager poolingHttpClientConnectionManager, RequestConfig requestConfig) {
CloseableHttpClient result = HttpClientBuilder
.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
return result;
}
#Bean
public RestTemplate restTemplate(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
And also important, you might need to change RestTemplate's default settings based on observation / load tests, RestTemplate doesn't necessary use the whole pool to prevent a host from hijacking it.
You can read more at my blog Troubleshooting Spring's RestTemplate Requests Timeout
From Spring Docs
RestTemplate
The RestTemplate is the central Spring class for client-side HTTP
access. Conceptually, it is very similar to the JdbcTemplate,
JmsTemplate, and the various other templates found in the Spring
Framework and other portfolio projects. This means, for instance, that
the RestTemplate is thread-safe once constructed, and that you can use
callbacks to customize its operations.
Hence you can create your RestTemplate its safe to share with multiple threads invoking a REST call simultaneously.
You should also consider cost of creating and destroying an instance. If each thread or each rest call creates a dedicated RestTemplate it will hamper your apps performance.
Ref: https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
It would be better if you're injecting the services in the rest template if they have something in common. You can inject services with some common behavior in one rest template. This way you'll be able to implement some resuable code in say a parent class. Just because they all are a service, injection them in a single rest template might not be proper from design point of view.
I am trying to know how long a HttpConnection is kept alive when inactive, before a new connection is created via Spring rest Template. I looked at default Connection Time-Out and Read Time-Out parameters, but I believe these are used in the context of connection time out when the connection is not established due to some failure etc.
What I am looking for is, how long a connection is kept alive if there is no activity (or) inactive, and how to configure this via Spring Rest Template (or) the underlying mechanism.
By default RestTemplate uses SimpleClientHttpRequestFactory which in turn opens Java's HttpURLConnection which by default supports keep-alive under certain conditions. If you want more control over how connections are handled, you can create restTemplate with HttpComponentsClientHttpRequestFactory, which uses Apache HttpClient library, e.g:
#Bean
RestTemplate restTemplate(SimpleClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
You can also see some discussions here:
How to Reuse HttpUrlConnection?
Persistent HttpURLConnection in Java
How to use RestTemplate efficiently in Multithreaded environment?
If org.apache.httpcomponents:httpclient / org.apache.http.client.HttpClient is on the classpath (which it often might be), by default RestTemplate uses the HttpComponentsClientHttpRequestFactory which uses a HttpClientBuilder which by default uses a PoolingHttpClientConnectionManager and initializes it with connTimeToLive = -1.
So Connections in the pool never "time out", but are checked before use if they are closed/stale.
In our case for some reason the connections in the pool became stale, without the check noticing it, resulting in Socket Timeout Exceptions when being used after they rest some time in the pool (maybe a proxy caused this without properly terminating the connection..?).
We decided to modify the default like this:
#Bean
public RestTemplateBuilder restTemplateBuilder(ObjectMapper objectMapper) {
return new RestTemplateBuilder()
.requestFactory(this::requestFactory);
}
private HttpComponentsClientHttpRequestFactory requestFactory() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
connectionManager.setDefaultMaxPerRoute(10);
connectionManager.setMaxTotal(30);
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
so that after 30 seconds the connection is not reused anymore.
It also sets the maxPerRoute to 10 (instead of 5) and maxTotal to 30 (instead of 2*5 = 10).
Application is using Spring rest template to call a webservice and i am using
restTemplate.exchage(url) to call the webservice.
Currently we are not passing any timeout value for this webservice call, How can i set a timeout value for Spring Rest template.
You can use code similar to following for setting connection timeout:
RestTemplate restTemplate = new RestTemplate();
((SimpleClientHttpRequestFactory)restTemplate.getRequestFactory()).setConnectTimeout(2000);
If your wish to set read timeout, you can have code similar to following:
((SimpleClientHttpRequestFactory)restTemplate.getRequestFactory()).setReadTimeout(2000);
The time is given in milliseconds here. For more info, you can visit the documentation page.
RestTemplateBuilder introduced since Spring 1.4 could be used to set read and connect timeout settings for RestTemplate object. Here is sample code -
final RestTemplate restTemplate =
new RestTemplateBuilder()
.setConnectTimeout(Duration.ofMillis(connectTimeoutMillis))
.setReadTimeout(Duration.ofMillis(readTimeoutMillis))
.build();
I use this approach based on these threads
int DEFAULT_TIMEOUT = 5000;
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(DEFAULT_TIMEOUT)
.setConnectionRequestTimeout(DEFAULT_TIMEOUT)
.setSocketTimeout(DEFAULT_TIMEOUT)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.build();
Spring RestTemplate Connection Timeout is not working
Java : HttpClient 4.1.2 : ConnectionTimeout, SocketTimeout values set are not effective