Uploaded image for project: 'HttpComponents HttpCore'
  1. HttpComponents HttpCore
  2. HTTPCORE-463

Async client does not respect IOReactor's connection timeout setting

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 4.4.6
    • 4.4.7
    • 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

      Attachments

        Activity

          People

            Unassigned Unassigned
            dankraw Daniel Krawczyk
            Votes:
            2 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: