Uh oh!
There was an error while loading. Please reload this page.
Cap default httpx connection pool on the task-sdk Client - #67506
Conversation
``Client.__init__`` did not set explicit ``httpx.Limits``, so each Client inherited httpx's defaults of ``max_connections=100`` and ``max_keepalive_connections=10``. The supervisor's own ``_ensure_client`` capped at ``max_connections=10, max_keepalive_connections=1`` — so the two code paths that build a task-sdk Client diverged by an order of magnitude in their pool behaviour, with no documented reason and surprising resource use under high concurrency. Standardise on a single bounded default at the Client level: ``httpx.Limits(max_keepalive_connections=5, max_connections=20)``. The supervisor's lower-cap path is unchanged (it sets ``limits`` explicitly), and any caller that needs different limits can still pass ``limits=...`` via kwargs.
| # Cap the httpx connection pool. Without an explicit value httpx defaults to 100 max | ||
| # connections, which is far higher than a single task subprocess ever needs (the | ||
| # supervisor sets ``max_connections=10`` in ``_ensure_client``). A bounded default |
There was a problem hiding this comment.
This code is only run in the supervisor, so this comment makes no sense
potiuk
commented
Jun 5, 2026
You're right — closing this. Traced it through: the only real-network instantiation is Drafted-by: Claude Code (Opus 4.8); reviewed by @potiuk before posting |
Client.__init__did not set explicithttpx.Limits, so each Client inherited httpx's defaults ofmax_connections=100andmax_keepalive_connections=10. The supervisor's own_ensure_clientcapped atmax_connections=10, max_keepalive_connections=1— so the two code paths that build a task-sdk Client diverged by an order of magnitude in their pool behaviour, with no documented reason and surprising resource use under high concurrency.Reported as F-011 in the
apache/tooling-agentsL3 task-sdk sweep0920c77.Change
Standardise on a single bounded default at the Client level via
kwargs.setdefault("limits", httpx.Limits(max_keepalive_connections=5, max_connections=20)). The supervisor's lower-cap path is unchanged (it setslimitsexplicitly before passing to the Client), and any caller that needs different limits can still passlimits=...via kwargs.Choosing
(5, 20)rather than(1, 10): a non-supervisor Client (e.g. instantiated directly by tests, CLI, or future callers) may handle higher per-instance concurrency than a single task subprocess, so the default sits between the supervisor's tight cap and httpx's untenably-high default.Test plan
test_default_pool_limits_are_bounded— instantiates a real (non-mock-transport) Client and assertspool._max_connections == 20andpool._max_keepalive_connections == 5.test_pool_limits_can_be_overridden—limits=httpx.Limits(...)kwarg overrides the default.prek run ruffclean.prek run mypy-task-sdkclean.test_client.pysuite: 117 passed.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 4.7) following the guidelines