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
>
>

Reply via email to