pub struct RateLimiter { /* private fields */ }Expand description
Process-wide async rate limiter.
Enforces three invariants on every acquire:
- Global concurrency — at most
RateLimits::max_concurrent_fetchesin flight at once. - Global rate — at most
RateLimits::max_fetches_per_secondstarts in any rolling one-second window. - Per-source backoff — at least
RateLimits::per_source_backoff_msbetween consecutive starts to the same source name.
The returned Permit holds the concurrency slot for the lifetime of the
value; drop it when the fetch is done.
429 / Retry-After handling is split: the limiter only exposes the admin
hook sleep_for; the actual Retry-After
header parse and call lives at the Source::fetch call site, per
docs/SOURCES.md §6.
Implementations§
Source§impl RateLimiter
impl RateLimiter
Sourcepub fn new(limits: RateLimits) -> Self
pub fn new(limits: RateLimits) -> Self
Construct from the hard-coded RateLimits (the only public path).
Sourcepub async fn pace(&self, source: &str)
pub async fn pace(&self, source: &str)
Wait out the per-source interval for one ADDITIONAL request inside a
fetch that already holds a Permit.
#493. arXiv’s terms cap requests, and one arXiv attempt issues two
of them – the Atom feed, then the PDF – under a single acquire.
The second was previously unpaced, so even a perfectly serialised
caller sent two requests back to back.
Does not touch the concurrency slots: the caller already holds them,
and taking them again would deadlock at max_concurrent_for == 1,
which is exactly the arXiv case.
Sourcepub async fn acquire(&self, source: &str) -> Permit
pub async fn acquire(&self, source: &str) -> Permit
Block until a slot is available, then return a Permit.
Order of waits, in this exact sequence:
- global concurrency (semaphore acquire),
- global rate cap (sleep if the rolling-second window is full),
- per-source backoff (sleep until the source’s
nexttime).
Lock-acquisition order is always global_starts first, THEN
per_source_next. Any future call site that needs both locks MUST
follow the same order to keep the system deadlock-free.