Skip to content

HTTPCLIENT-2404: Add timeouts section to the HttpClient 5.6.x configuration guide - #48

Merged
ok2c merged 1 commit into
apache:masterfrom
shinseongsu:HTTPCLIENT-2404-timeouts
Nov 1, 2026
Merged

ok2c merged 1 commit into
apache:masterfrom
shinseongsu:HTTPCLIENT-2404-timeouts

Conversation

@shinseongsu

@shinseongsu shinseongsu commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

For HTTPCLIENT-2404.

Oleg suggested in the issue that this belongs in the configuration guide rather than a separate document, so I added a Timeouts section to the 5.6.x guide. It covers which timeout applies to each phase of a request, how the socket timeout set at different levels overrides each other, and that none of them is a deadline.

To make sure I wasn't just repeating my own assumptions, I tested each statement against 5.6.5 with a couple of local servers, one that never answers and one that sends the body a byte at a time. Times are in seconds:

Case Settings Classic Async
connect, 2 unreachable addresses connect=1 2.0 2.0
TLS, server never answers so=5, connect=1 1.1 1.1
TLS, server never answers so=5, connect=1, handshake=3 3.0 3.0
TLS, server never answers so=5, connect=4, response=1 4.0 4.0
waiting for response so=4, socket=2, response=1 1.0 1.0
waiting for response so=1, socket=1, response=3 3.0 3.1
body trickling in over 3.2s response=1 200 200

Retries were off on the classic client. I can share the test program if that helps.

Before, the guide ends at the caching level:

After, with the new section in the red box:

Two things came up while testing that I left out of the guide, because I don't know if they're intended:

  • If the TLS handshake fails, the classic transport tries the next resolved address and handshakes again, but async doesn't. Against localhost (127.0.0.1 and ::1) the classic client waited 2x the handshake timeout.
  • On the async client, connectionRequestTimeout doesn't seem to fire unless something else happens in the pool. With a 1s timeout and the only connection stuck on a request that never finishes, the second request was still waiting after 10s. I couldn't find any caller of validatePendingRequests(). If it's a bug I can open a separate issue.

Should the connection lifetime settings (timeToLive, idleTimeout, ...) go in here too, or is this enough for the issue?

…ration guide

Describe which timeout applies to each phase of a request, how the socket
timeout set at different levels overrides each other, and that the
timeouts limit inactivity rather than the total time of a request.
@ok2c

ok2c commented Oct 31, 2026

Copy link
Copy Markdown
Member

@shinseongsu I will review the change-set more thoroughly tomorrow but overall looks awesome!

If the TLS handshake fails, the classic transport tries the next resolved address and handshakes again, but async doesn't. Against localhost (127.0.0.1 and ::1) the classic client waited 2x the handshake timeout.

This looks wrong. Both transports should behave consistently. Please raise a JIRA for this issue.

On the async client, connectionRequestTimeout doesn't seem to fire unless something else happens in the pool. With a 1s timeout and the only connection stuck on a request that never finishes, the second request was still waiting after 10s. I couldn't find any caller of validatePendingRequests(). If it's a bug I can open a separate issue.

This sounds possible. One may need to be willing to run an extra watcher thread to enforce lease timeouts on an idle pool, but we should investigate if this is not a defect. Please raise a JIRA for this issue as well.

Should the connection lifetime settings (timeToLive, idleTimeout, ...) go in here too, or is this enough for the issue?

It would be really nice to have connection lifetime settings covered in more details, too. Please do so, if you have time and inclination to contribute that as well.

@shinseongsu

Copy link
Copy Markdown
Contributor Author

Thanks for the quick feedback, @ok2c!

I don't have a JIRA account yet — I've requested one and I'm waiting for it to be approved. Once I have access, I'll file two separate issues for:

  1. the TLS handshake retry inconsistency between the classic and async transports, and
  2. connectionRequestTimeout not firing on the async client when the pool is otherwise idle,

and I think the discussion about both is best continued in those issues. I'll link them back here.

I'll also take a look at covering the connection lifetime settings (timeToLive, idleTimeout, etc.) in more detail, either in this PR or as a follow-up.

None of these settings apply during the TLS handshake. The TLS handshake timeout is used
instead.

Response timeout may be unsupported by HTTP transports with message multiplexing such

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shinseongsu The HTTP/2 transport will support (conditionally) as of 5.7. I think this statement can be omitted

| Host name resolution | none | - |
| TCP connect | [ConnectionConfig](/httpcomponents-client-5.6.x/current/httpclient5/apidocs/org/apache/hc/client5/http/config/ConnectionConfig.html) `connectTimeout` | 3 minutes |
| TLS handshake | [TlsConfig](/httpcomponents-client-5.6.x/current/httpclient5/apidocs/org/apache/hc/client5/http/config/TlsConfig.html) `handshakeTimeout` | the connect timeout |
| Request and response exchange | the socket timeout, see [Socket Timeout](#Socket_Timeout) | 3 minutes (classic), no timeout (async) |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 minutes (classic), no timeout (async)

@shinseongsu This looks wrong. Thank you for pointing that out. This should be fixed.

@ok2c

ok2c commented Nov 1, 2026

Copy link
Copy Markdown
Member

@shinseongsu Everything is fine as is. Thank you so much for this contribution.

@ok2c
ok2c merged commit 0cb6077 into apache:master Nov 1, 2026
@ok2c

ok2c commented Nov 1, 2026

Copy link
Copy Markdown
Member

@shinseongsu Updated site content deployed to hc.apache.org

@shinseongsu

Copy link
Copy Markdown
Contributor Author

@ok2c I now have a JIRA account and filed the two issues:

  • HTTPCLIENT-2436: async does not retry the next resolved address after a TLS handshake failure, unlike classic
  • HTTPCLIENT-2437: async connectionRequestTimeout does not fire on an otherwise idle pool

I'll continue the discussion on both in those issues. I'll also look at covering the connection lifetime settings (timeToLive, idleTimeout, etc.) in more detail as a follow-up.

@ok2c

ok2c commented Nov 2, 2026

Copy link
Copy Markdown
Member

@shinseongsu I put together a fix for the default socket consistency problem: apache/httpcomponents-client#923

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants