Skip to content

Commit 6aee03c

Browse files
Document rate-limit semantics precisely; mention it in the README
The PyPI-facing README still described the package as digest-auth only. In the API reference, spell out the details a user needs to avoid surprises: rate must be finite; per-domain buckets are keyed on host only; Retry-After is honored on 429 only, delays just the request that received it, and its sleep counts against the session ClientTimeout (hence the 60s default cap); configuration is fixed at construction; and the rate limiter should be listed last so internal retries by other middlewares are also throttled.
1 parent f3cf281 commit 6aee03c

2 files changed

Lines changed: 34 additions & 12 deletions

File tree

‎README.rst‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@ aiohttp-client-middlewares
2626
Reusable client middlewares for aiohttp.
2727

2828
``aiohttp-client-middlewares`` is a small, pure-Python collection of
29-
ready-to-use *client* middlewares for ``aiohttp``. It currently provides
30-
``DigestAuthMiddleware``, vendored from aiohttp core; this package is the
31-
canonical home for it going forward.
29+
ready-to-use *client* middlewares for ``aiohttp``. It currently provides:
30+
31+
- ``DigestAuthMiddleware`` -- HTTP Digest authentication, vendored from
32+
aiohttp core; this package is the canonical home for it going forward.
33+
- ``RateLimitMiddleware`` -- client-side token-bucket rate limiting with
34+
optional per-domain buckets and ``Retry-After`` handling.
3235

3336
Middlewares plug into ``aiohttp.ClientSession`` through the client
3437
middleware API introduced in aiohttp 3.12, so they can wrap every outgoing

‎docs/api.rst‎

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,32 +80,51 @@ Digest authentication
8080
Rate limiting
8181
-------------
8282

83-
.. class:: RateLimitMiddleware(rate=10.0, burst=10, per_domain=False, respect_retry_after=True, max_retry_after=300.0)
83+
.. class:: RateLimitMiddleware(rate=10.0, burst=10, per_domain=False, respect_retry_after=True, max_retry_after=60.0)
8484

8585
Client middleware that throttles outgoing requests with a token bucket.
8686

8787
:param float rate: Sustained request rate, in requests per second. Must be
88-
greater than 0.
88+
a positive, finite number.
8989
:param int burst: Number of requests allowed to go out back-to-back before
9090
throttling kicks in. Must be at least 1.
9191
:param bool per_domain: Keep an independent bucket per target host instead
92-
of a single global bucket. The per-host buckets are never evicted, so only
93-
enable this for a bounded, trusted set of hosts.
92+
of a single global bucket. Buckets are keyed on the URL host only (port
93+
and scheme are not distinguished) and are never evicted, so only enable
94+
this for a bounded, trusted set of hosts.
9495
:param bool respect_retry_after: Sleep for the duration of a numeric
9596
``Retry-After`` header on an HTTP 429 response before returning it to the
96-
caller.
97+
caller. Only the request that received the 429 sleeps -- concurrent
98+
requests are not held back -- and the response is returned as-is
99+
afterwards (there is no automatic retry). Other statuses that may carry
100+
``Retry-After`` (such as 503) are not inspected.
97101
:param max_retry_after: Upper bound, in seconds, on how long a ``Retry-After``
98-
header may make the client sleep. Must be ``None`` (no cap) or a
99-
non-negative, finite number. A server-sent ``Retry-After`` that is itself
100-
non-finite (``inf``/``nan``) or non-positive is always ignored, so a
101-
hostile server cannot stall the client indefinitely.
102+
header may make the client sleep (default ``60.0``; ``0.0`` disables the
103+
sleep entirely). Must be ``None`` (no cap) or a non-negative, finite
104+
number. A server-sent ``Retry-After`` that is itself non-finite
105+
(``inf``/``nan``) or non-positive is always ignored, so a hostile server
106+
cannot stall the client indefinitely. The sleep happens inside the request
107+
and counts against the session's :class:`~aiohttp.ClientTimeout` (whose
108+
default ``total`` is 300 seconds), so keep the cap well below your total
109+
timeout or the request will fail with a timeout error instead of returning
110+
the 429 response.
102111
:type max_retry_after: float or None
103112

104113
The middleware delays each request until the bucket grants it a slot, so the
105114
client never sends faster than ``rate`` requests per second while still
106115
allowing short bursts of up to ``burst`` requests. Slots are served in strict
107116
FIFO order.
108117

118+
Configuration is fixed at construction time: changing the attributes of an
119+
existing instance does not reconfigure buckets that were already built.
120+
121+
Middleware order matters: middlewares listed earlier wrap the ones listed
122+
later, and a middleware that retries internally (for example,
123+
:class:`DigestAuthMiddleware` replaying a request after a 401) re-invokes
124+
only the middlewares listed *after* it. List ``RateLimitMiddleware`` last so
125+
that every request hitting the wire -- including such replays -- is
126+
throttled.
127+
109128
``rate``, ``burst`` and ``max_retry_after`` are validated on construction and
110129
raise :exc:`ValueError` if out of range.
111130

0 commit comments

Comments
 (0)