HttpRequestConfig : our POJO containing timeout settings and connection pool settings.
connectionManager (PoolingAsyncClientConnectionManagerBuilder): ``` connectionManagerBuilder.setConnectionConfigResolver( (route) -> ConnectionConfig.custom() // 30 seconds .setTimeToLive(TimeValue.of(HttpClientConfigDefaults.DEFAULT_CONNECTION_TTL)) // default 2 seconds for most clients .setConnectTimeout(Timeout.of(httpRequestConfig.getConnectTimeout())) .build() ); // force http 1.1 currently connectionManagerBuilder.setDefaultTlsConfig(TlsConfig.custom().setVersionPolicy(getHttpVersionPolicy(httpRequestConfig)).build()); // sslContext with some trustStore setup and a custom hostnameVerifier connectionManagerBuilder.setTlsStrategy(ClientTlsStrategyBuilder.create().setSslContext(sslContext).setHostnameVerifier(hostnameVerifier).build()); ``` IOReactor: ``` IOReactorConfig ioReactorConfig = IOReactorConfig.custom() // 30 seconds default .setSoTimeout(Timeout.of(HttpClientConfigDefaults.DEFAULT_READ_TIMEOUT)) .build(); ``` CloseableHttpAsyncClient (clients are cached essentially per httpRequestConfig) ``` RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(StandardCookieSpec.RELAXED).build(); HttpAsyncClientBuilder.create() .disableAutomaticRetries() .setConnectionManagerShared(true) .setDefaultRequestConfig(defaultRequestConfig) // from above .setIOReactorConfig(ioReactorConfig) // from above .setConnectionManager(connectionManager) .build(); ``` our requestTimeout configuration (HttpClientContext): ``` HttpClientContext httpClientContext = new HttpClientContext(); var requestConfigBuilder = RequestConfig.custom() // 10 seconds for this particular case .setResponseTimeout(Timeout.of(httpRequestConfig.getSocketTimeout())) // default 2 seconds (set from connectTimeout by default) .setConnectionRequestTimeout(Timeout.of(httpRequestConfig.getConnectionRequestTimeout())); httpClientContext.setRequestConfig(requestConfigBuilder.build()); ``` request call (async with callback): ``` // the last parameter is our class implementing FutureCallback Future<Message<HttpResponse, RES>> clientFuture = asyncHttpClient.execute(asyncRequestProducer, responseConsumer, null, httpClientContext, this); // callTimeout is essentially connectTimeout + socketTimeout by default. return clientFuture.get(callTimeout, TimeUnit.MILLISECONDS); ``` stack trace (when this specific timeout happens): ``` at org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.client5.http.impl.async.InternalAbstractHttpAsyncClient$2.failed(InternalAbstractHttpAsyncClient.java:364) [httpclient5-5.4.4.jar:5.4.4] at org.apache.hc.client5.http.impl.async.AsyncRedirectExec$1.failed(AsyncRedirectExec.java:246) [httpclient5-5.4.4.jar:5.4.4] at org.apache.hc.client5.http.impl.async.AsyncProtocolExec$1.failed(AsyncProtocolExec.java:295) [httpclient5-5.4.4.jar:5.4.4] at org.apache.hc.client5.http.impl.async.AsyncConnectExec$2.failed(AsyncConnectExec.java:233) [httpclient5-5.4.4.jar:5.4.4] at org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackContribution.java:52) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager$4.failed(PoolingAsyncClientConnectionManager.java:482) [httpclient5-5.4.4.jar:5.4.4] at org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:166) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.java:79) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.FutureContribution.failed(FutureContribution.java:52) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackContribution.java:52) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.ssl.SSLIOSession$1.exception(SSLIOSession.java:233) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.ssl.SSLIOSession$1.timeout(SSLIOSession.java:223) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.InternalDataChannel.onTimeout(InternalDataChannel.java:170) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.InternalChannel.checkTimeout(InternalChannel.java:67) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.SingleCoreIOReactor.checkTimeout(SingleCoreIOReactor.java:239) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.SingleCoreIOReactor.validateActiveChannels(SingleCoreIOReactor.java:166) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:128) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:92) [httpcore5-5.3.4.jar:5.3.4] at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) [httpcore5-5.3.4.jar:5.3.4] at java.lang.Thread.run(Thread.java:840) [?:?] Caused by: java.net.SocketTimeoutException: 2 SECONDS at org.apache.hc.core5.io.SocketTimeoutExceptionFactory.create(SocketTimeoutExceptionFactory.java:50) ~[httpcore5-5.3.4.jar:5.3.4] ``` I hope the details are enough. Thanks. On Wed, Jul 30, 2025 at 8:14 PM Oleg Kalnichevski <ol...@apache.org> wrote: > On Wed, 2025-07-30 at 12:54 +0200, Cenk Pekyaman wrote: > > httpclient5 version: 5.4.4 > > httpCore5 version: 5.3.4 > > Java version: 17 (21 since recently) > > > > We are using http-client-5 under our api-client layer with async + > > TLS. > > Once in a while, we get a timeout exception like this: > > "java.net.SocketTimeoutException: 2 SECONDS" in some requests. and > > from the > > stack trace, we see that the exception is coming from > > "InternalDataChannel.onTimeout". but the value we see is actually the > > connectTimeout, not the readTimeout(socketTimeout) we set for the > > request. > > > > The explanation we came up with is that, the client completes the > > initial > > connect step with "InternalConnectChannel" and then the socket is > > handed > > over to "InternalDataChannel" to do the TLS handshake in "startTls", > > which > > either takes too long to complete, or hangs. We came to this > > conclusion > > because the code flow seems to have TLS handshake after connect in > > sessionRequest.complete callback and handshake uses connectTimeout by > > default (and also our request traces don't show a request reaching > > the > > server for such cases). > > > > Our question(s): > > 1. Is that really what is happening here. > > I cannot say. I need more context / details > > > 2. Is there anything specific we might check to find the root cause. > > I need to see exactly how timeouts get configured in your code and I > need to see the exact exception stack trace to be able to tell more. > > > 3. if it is a "tls handshake too long" issue, can http-client throw a > > specific exception for that. > > > > I think we could do that. > > Oleg > > --------------------------------------------------------------------- > To unsubscribe, e-mail: httpclient-users-unsubscr...@hc.apache.org > For additional commands, e-mail: httpclient-users-h...@hc.apache.org > >