Hi,

I created it here: https://issues.apache.org/jira/browse/HTTPCLIENT-2386.
I tried to summarize it a bit better, I hope the ticket format is ok.

Thanks.

On Thu, Jul 31, 2025 at 12:27 PM Oleg Kalnichevski <ol...@apache.org> wrote:

> On Thu, 2025-07-31 at 10:15 +0200, Cenk Pekyaman wrote:
> > HttpRequestConfig : our POJO containing timeout settings and
> > connection
> > pool settings.
> >
> > connectionManager (PoolingAsyncClientConnectionManagerBuilder):
> > ```
> > connectionManagerBuilder.setConnectionConfigResolver(
> >    (route) -> ConnectionConfig.custom()
> >                        // 30 seconds
> >
> > .setTimeToLive(TimeValue.of(HttpClientConfigDefaults.DEFAULT_CONNECTI
> > ON_TTL))
> >                        // default 2 seconds for most clients
> >
> >  .setConnectTimeout(Timeout.of(httpRequestConfig.getConnectTimeout())
> > )
> >                        .build()
> > );
> > // force http 1.1 currently
> > connectionManagerBuilder.setDefaultTlsConfig(TlsConfig.custom().setVe
> > rsionPolicy(getHttpVersionPolicy(httpRequestConfig)).build());
> > // sslContext with some trustStore setup and a custom
> > hostnameVerifier
> > connectionManagerBuilder.setTlsStrategy(ClientTlsStrategyBuilder.crea
> > te().setSslContext(sslContext).setHostnameVerifier(hostnameVerifier).
> > build());
> > ```
> >
> > IOReactor:
> > ```
> > IOReactorConfig ioReactorConfig =
> >                 IOReactorConfig.custom()
> >                          // 30 seconds default
> >
> > .setSoTimeout(Timeout.of(HttpClientConfigDefaults.DEFAULT_READ_TIMEOU
> > T))
> >                         .build();
> > ```
> >
> > CloseableHttpAsyncClient (clients are cached essentially per
> > httpRequestConfig)
> > ```
> > RequestConfig defaultRequestConfig =
> > RequestConfig.custom().setCookieSpec(StandardCookieSpec.RELAXED).buil
> > d();
> >
> > 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.getConnect
> > ionRequestTimeout()));
> > 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:16
> > 6)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.jav
> > a: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(Asyn
> > cRedirectExec.java:246)
> > [httpclient5-5.4.4.jar:5.4.4]
> > at
> > org.apache.hc.client5.http.impl.async.AsyncProtocolExec$1.failed(Asyn
> > cProtocolExec.java:295)
> > [httpclient5-5.4.4.jar:5.4.4]
> > at
> > org.apache.hc.client5.http.impl.async.AsyncConnectExec$2.failed(Async
> > ConnectExec.java:233)
> > [httpclient5-5.4.4.jar:5.4.4]
> > at
> > org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackCo
> > ntribution.java:52)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:16
> > 6)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.jav
> > a:79)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManag
> > er$4.failed(PoolingAsyncClientConnectionManager.java:482)
> > [httpclient5-5.4.4.jar:5.4.4]
> > at
> > org.apache.hc.core5.concurrent.BasicFuture.failed(BasicFuture.java:16
> > 6)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.ComplexFuture.failed(ComplexFuture.jav
> > a:79)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.FutureContribution.failed(FutureContri
> > bution.java:52)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.concurrent.CallbackContribution.failed(CallbackCo
> > ntribution.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.j
> > ava:223)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.InternalDataChannel.onTimeout(InternalDat
> > aChannel.java:170)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.InternalChannel.checkTimeout(InternalChan
> > nel.java:67)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.SingleCoreIOReactor.checkTimeout(SingleCo
> > reIOReactor.java:239)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.SingleCoreIOReactor.validateActiveChannel
> > s(SingleCoreIOReactor.java:166)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreI
> > OReactor.java:128)
> > [httpcore5-5.3.4.jar:5.3.4]
> > at
> > org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(Abstr
> > actSingleCoreIOReactor.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(SocketTim
> > eoutExceptionFactory.java:50)
> > ~[httpcore5-5.3.4.jar:5.3.4]
> > ```
> >
> > I hope the details are enough.
> >
> > Thanks.
> >
>
> This looks like a bug (or at least inconsistency between the classic
> and the async transports). The former uses socket timeout as a default
> whereas the latter uses the connect timeout.
>
> Please raise a JIRA ticket for this issue.
>
> Oleg
>
>
> > 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
> > >
> > >
>
>
> ---------------------------------------------------------------------
> 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