Skip to content

feat(http,oss): expose max idle timeout for pooled connections - #1733

Open
Moonpuck wants to merge 1 commit into
alibaba:release/0.9from
Moonpuck:feat/http-pool-max-idle-timeout-0.9
Open

Moonpuck wants to merge 1 commit into
alibaba:release/0.9from
Moonpuck:feat/http-pool-max-idle-timeout-0.9

Conversation

@Moonpuck

@Moonpuck Moonpuck commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

What this does

The socket pool already supports an expiration (TTL) that was never exposed
through the API. This adds:

  • Client::set_max_idle_timeout() / Client::max_idle_timeout()
  • objstore::ClientOptions::max_idle_timeout_us

Default stays -1 (never expire), so existing behaviour is unchanged.

The pool is a thread_local PooledDialer shared by all clients within a
std::thread and created on the first request, so the TTL comes from the first
client that sends a request. This is documented on new_http_client().

Hardening fixes

A finite TTL could never reach the pool before, so two latent problems are
fixed here:

  • A zero TTL made evict() compute near_expire == now, tripping
    assert(near_expire > now) in debug builds and spinning the timer forever in
    release builds. Zero is now rejected as -1 in PooledDialer::init().
  • evict() computed near_expire with a bare TTL_us + now, which wraps
    around for extreme values. Switched to sat_add().

Tests

net/http/test/client_function_test.cpp:

  • max_idle_timeout_expires_pooled_connection
  • zero_max_idle_timeout_means_no_expiration

Both run the client on a dedicated std::thread, because the pool is
thread_local and initialized once -- a TTL set on a later client would
otherwise be silently ignored.

Note

There is a separate, hand-written PR against main for the same feature.
It is not a cherry-pick in either direction: main routes this through
net/http/dialer.*, which does not exist on this branch. Please do not add
need-backport here.

The socket pool already supports an expiration (TTL) that was never exposed
through the API. Add Client::set_max_idle_timeout()/max_idle_timeout() and
ClientOptions::max_idle_timeout_us, defaulting to -1 (never expire).

The pool is a thread_local PooledDialer shared by all clients within a
std::thread and created on the first request, so the TTL comes from the first
client that sends a request; this is documented on new_http_client().

Two hardening fixes, since a finite TTL could never reach the pool before:

  - A zero TTL made evict() compute near_expire == now, tripping
    assert(near_expire > now) in debug builds and spinning the timer forever
    in release builds. Zero is now rejected as -1 in PooledDialer::init().
  - evict() computed near_expire with a bare TTL_us + now, which wraps around
    for extreme values. Switched to sat_add().

Test: net/http/test/client_function_test.cpp
  max_idle_timeout_expires_pooled_connection
  zero_max_idle_timeout_means_no_expiration
@Moonpuck
Moonpuck requested review from Coldwings and lihuiba November 9, 2026 02:25
Comment thread net/http/client.h
// Create an HTTP client. Without cookie_jar, "Set-Cookies" headers are ignored.
// Note: HTTP clients within the same std::thread share TLS config and connection pool.
// Use separate std::threads for different TLS configurations.
// Note: HTTP clients within the same std::thread share TLS config and connection

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use the term vcpu instead of std::thread

Comment thread net/http/client.h
std::string m_proxy_auth;
std::string m_user_agent;
uint64_t m_timeout = -1UL;
uint64_t m_max_idle_timeout = -1UL;

@lihuiba lihuiba Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do NOT use UL or L (long), use ULL instead throughout Photon, for portability.
It's OK in 0.9

Comment thread net/http/client.h
// -1UL (default) keeps idle connections until the peer closes them; 0 is
// treated as -1UL. Must be set before the first request; see
// new_http_client() for the per-std::thread sharing behaviour.
void set_max_idle_timeout(uint64_t timeout_us) { m_max_idle_timeout = timeout_us; }

@lihuiba lihuiba Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

connection_idle_expiration is preferred. "connection" is more informative, and "expiration" is aligned with main.

@lihuiba

lihuiba commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator

PR to main is OK, and rely on auto backport for older releases.

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