Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
4.4.6
-
None
-
None
Description
Hello, I've noticed an issue with the async client where connection timeout setting is not respected when configured for `IOReactor` object.
When I create the client like this:
CloseableHttpAsyncClient createAsyncClient() {
return HttpAsyncClientBuilder.create()
.setConnectionManager(connectionManager())
.build();
}
where connection manager is configured as follows:
private PoolingNHttpClientConnectionManager connectionManager() { IOReactorConfig reactorConfig = IOReactorConfig.custom() .setConnectTimeout(config.getConnectionTimeout()) // this doesn't work .setSoTimeout(config.getSocketTimeout()) // this works .setSelectInterval(config.getTimeoutCheckInterval()) .setIoThreadCount(config.getNioThreads()) .setTcpNoDelay(true) .build(); ConnectingIOReactor reactor = new DefaultConnectingIOReactor(reactorConfig, threadFactory()); return new PoolingNHttpClientConnectionManager(reactor); }
the `setConnectTimeout(...)` option is not respected.
After some longer time (this might be some system default? - 30 or 120 seconds, depends on the system I run the code) I get an exception thrown from a native method:
11:27:02.223 [pool-2-thread-1] DEBUG org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager - Connection request failed java.net.ConnectException: Operation timed out at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:716) at org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processEvent(DefaultConnectingIOReactor.java:171) at org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processEvents(DefaultConnectingIOReactor.java:145) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:348) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:194) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64) at java.lang.Thread.run(Thread.java:745)
On the other hand the socket timeout setting works as expected.
...
After debugging this, I found a way to cope with that by adding a default request config on the client:
CloseableHttpAsyncClient createAsyncClient() { return HttpAsyncClientBuilder.create() .setConnectionManager(connectionManager()) .setDefaultRequestConfig(requestConfig()) // this works .build(); } private RequestConfig requestConfig() { return RequestConfig.custom() .setConnectTimeout(config.getConnectionTimeout()) // this works .setSocketTimeout(config.getSocketTimeout()) // this works as well .build(); }
This way it works, I get an exception after specified time:
11:05:37.267 [pool-2-thread-1] DEBUG org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager - Connection request failed java.net.ConnectException: null at org.apache.http.nio.pool.RouteSpecificPool.timeout(RouteSpecificPool.java:168) at org.apache.http.nio.pool.AbstractNIOConnPool.requestTimeout(AbstractNIOConnPool.java:584) at org.apache.http.nio.pool.AbstractNIOConnPool$InternalSessionRequestCallback.timeout(AbstractNIOConnPool.java:851) at org.apache.http.impl.nio.reactor.SessionRequestImpl.timeout(SessionRequestImpl.java:183) at org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processTimeouts(DefaultConnectingIOReactor.java:210) at org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor.processEvents(DefaultConnectingIOReactor.java:155) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:348) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:194) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64) at java.lang.Thread.run(Thread.java:745)
The test I performed looked something like this (groovy/spock):
def "test bare client"() { given: def client = asyncClientFactory.createAsyncClient() // creates client with some short connection timeout client.start() when: HttpGet request = new HttpGet("http://10.0.0.0") // call some non-routable IP to trigger the connection timeout def response = client.execute(request, null).get() then: def e = thrown(ExecutionException) e.cause instanceof ConnectException cleanup: client.close() }
Regards,
Daniel