pub struct RateLimited {
pub kind: RateLimitKind,
pub retry_after: Option<Duration>,
pub remaining: Option<u64>,
pub reset_unix_secs: Option<u64>,
}Expand description
An exhausted rate limit, as a state something can display.
The Definition of Done asks for “a distinct, displayable state rather than an opaque error”, and the distinction is the point: a rate limit is the one failure in this gateway that is neither the operator’s fault nor a reason to change anything. It resolves by waiting, and the operator’s only legitimate question is “how long”, which is what every field here answers.
Fields§
§kind: RateLimitKind§retry_after: Option<Duration>retry-after, when GitHub sent one in the integer-seconds form.
remaining: Option<u64>x-ratelimit-remaining.
reset_unix_secs: Option<u64>x-ratelimit-reset, a Unix timestamp in seconds.
Implementations§
Source§impl RateLimited
impl RateLimited
Sourcepub fn detect(error: &GithubError) -> Option<Self>
pub fn detect(error: &GithubError) -> Option<Self>
Whether this failure is GitHub declining to serve any more requests for now — and if so, which limit.
§Why this is narrower than “remaining is zero”
GitHub attaches x-ratelimit-* to every response, successful ones
included. A 404 that happens to arrive on the request that exhausted
the hourly quota therefore carries x-ratelimit-remaining: 0 while
having nothing to do with rate limiting — and reporting it as a rate
limit would tell the operator to wait for a repository name that will
never resolve.
So the status has to be one GitHub actually rate-limits with — 403 or
429 — before the headers are read at all. And a 403 is not enough on
its own, because 403 is also how GitHub refuses a missing permission.
The two questions are therefore answered in order:
Is this a rate limit at all? Only a 429, or a 403 whose message
says “rate limit”, qualifies. The message is the same evidence
crate::AuthenticatedClient already uses to keep a rate limit from
being misreported as an authentication lockout, and reading it the same
way here is what keeps the two layers agreeing. Everything else is a
permissions answer, whatever the headers say — see
a_permissions_403_that_lands_on_an_exhausted_quota_is_still_forbidden.
Which limit is it? Now the headers matter.
x-ratelimit-remaining: 0 is the primary limit and takes precedence,
because a 429 sent while the hourly quota is exhausted resets on the
hourly schedule rather than on a short back-off. Anything else is the
secondary limit.
Sourcepub fn delay_from(&self, now: Timestamp) -> Duration
pub fn delay_from(&self, now: Timestamp) -> Duration
How long to wait before asking again, given the current instant.
retry-after first, because it is GitHub’s explicit instruction;
x-ratelimit-reset second, because a primary limit says when rather than
how long; DEFAULT_RATE_LIMIT_BACKOFF when neither is usable, because
“GitHub said stop and named no time” must still stop.
Clamped to MAX_RATE_LIMIT_BACKOFF. A remote header is not allowed to
decide how long this product stays dark.
Trait Implementations§
Source§impl Clone for RateLimited
impl Clone for RateLimited
Source§fn clone(&self) -> RateLimited
fn clone(&self) -> RateLimited
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for RateLimited
Source§impl Debug for RateLimited
impl Debug for RateLimited
Source§impl Display for RateLimited
impl Display for RateLimited
impl Eq for RateLimited
Source§impl PartialEq for RateLimited
impl PartialEq for RateLimited
impl StructuralPartialEq for RateLimited
Auto Trait Implementations§
impl Freeze for RateLimited
impl RefUnwindSafe for RateLimited
impl Send for RateLimited
impl Sync for RateLimited
impl Unpin for RateLimited
impl UnsafeUnpin for RateLimited
impl UnwindSafe for RateLimited
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.