In this article we will try to cover why it’s important to define timeouts for out bound rest calls.
Before configuring any timeout let’s understand below some common exceptions for http outbound calls,
Connection timeout
maximum time to wait for the other side to answer "yes, I'm here, let's talk" when creating a new connection, (ConnectTimeout eventually calls socket.connect(address, timeout), If the connection is not established within the ConnectTimeout specified by you or the library you are using then, you get an error 'connect timedout
Socket timeout
Is the timeout for waiting for data or, put differently, a maximum period inactivity between two consecutive data packets
Read timeout
Read timeout can happen when there is successful connection established between client and the server and there is an inactivity between data packets while waiting for the server response.
Write timeout
Similar to Read timeout, write timeout can happen when there is successful connection established between client and server, and there is inactivity between data packets while sending the request to the server.
The important topic to remember here is that based on the choice of library we use for outbound calls it’s very important that we configure the properties to handle the above mentioned one’s and handle the exception gracefully.
Apache Camel
If we are using Apache Camel ‘http’ component to make the outbound calls then we can configure these properties in following ways, please note that if we don’t define this properties the default values is -1! means connection will never timeout and can have advert effect on the application performance overall.
camel.property
http.urlProxy = http4://ThirdPartyServers?throwExceptionOnFailure=false&httpClient.socketTimeout=${rest.timeout.millis}&httpClient.connectTimeout=${rest.timeout.millis}
Route Builder Class
@Override
public void configure() throws Exception {
configureTimeout();
}
private void configureTimeout() {
HttpComponent httpComponent = getContext().getComponent("http4", HttpComponent.class);
httpComponent.setConnectionTimeToLive(VALUE_IN_MILI);// for closing the idle connection - in milliseconds
httpComponent.setSocketTimeout(VALUE_IN_MILI); //socket timeout - in milliseconds
httpComponent.setConnectTimeout(VALUE_IN_MILI); // connection timeout - in milliseconds*/
}
Rest Template
In a similar manner for rest template we could define as follows,
final RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(VALUE_IN_MILI)
.setConnectTimeout(VALUE_IN_MILI)
.setSocketTimeout(VALUE_IN_MILIs)
.build();
final HttpClient httpClient = HttpClients.custom()
.setConnectionTimeToLive(VALUE_IN_MILI, SECONDS)
.setRetryHandler((IOException exception, int executionCount, HttpContext context) -> {
return executionCount <= 3;
})
.setServiceUnavailableRetryStrategy(new DefaultServiceUnavailableRetryStrategy(3, 1))
.setDefaultRequestConfig(requestConfig)
.build();
final RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
WebClient
And in a similar manner below is how we could define it in web client,
public WebClient getWebClient()
{
HttpClient httpClient = HttpClient.create()
.tcpConfiguration(client ->
client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, VALUE_IN_MILI)
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(rest.timeout.millis))
.addHandlerLast(new WriteTimeoutHandler(rest.timeout.millis))));
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient.wiretap(true));
return WebClient.builder()
.baseUrl("http://localhost:3000")
.clientConnector(connector)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
Summary
All in all it’s very important to configure these values i.e. connection timeout, read timeout, socket timeout etc so as to terminate the connections after waiting for a specific amount of time rather keeping the connection open indefinitely which can bring issues to overall application performance and stability.
Top comments (0)