Skip to main content

BackoffPolicy

Struct BackoffPolicy 

Source
pub struct BackoffPolicy {
    pub first_attempt_grace: Duration,
    pub base: Duration,
    pub ceiling: Duration,
    pub max_attempts: u32,
}
Expand description

When a pending entry becomes eligible for another relay attempt.

Why: ADR-0034 §2 says “Console retries with backoff” and the first cut had none — every pending entry was re-relayed every 60 s, each non-ack rewriting the full base64 body plus two fsyncs. Until step 4 binds a listener that is every delivery, forever. What: a grace period for a never-attempted entry, exponential spacing keyed on attempts, a ceiling, and a hard stop. Pure — BackoffPolicy::is_due takes now so the rules are testable without sleeping. Test: backoff_holds_off_a_freshly_spooled_entry, backoff_spacing_grows_with_attempts, backoff_respects_the_ceiling, backoff_stops_at_max_attempts.

Fields§

§first_attempt_grace: Duration

How long a never-attempted entry is left alone after being spooled.

Set to the relay timeout: within that window the request path that spooled it may still be relaying it, and its claim has not necessarily been taken yet at the instant the sweep lists the directory.

§base: Duration

Spacing after the first failure; doubles per subsequent attempt.

§ceiling: Duration

Upper bound on the spacing, however many attempts have failed.

§max_attempts: u32

After this many failed attempts the entry is never relayed again.

It is NOT deleted — it stays on disk and keeps the health signal red, because an undeliverable webhook is an operator problem, not garbage. The cap exists so a permanently unrelayable entry stops costing a full-body rewrite and two fsyncs on every tick.

Implementations§

Source§

impl BackoffPolicy

Source

pub fn delay_after(&self, attempts: u32) -> Duration

Spacing required after attempts failures.

base << (attempts - 1), saturating into BackoffPolicy::ceiling. The shift is bounded before it is applied, so a large attempt count cannot overflow into a small delay.

Test: backoff_spacing_grows_with_attempts, backoff_respects_the_ceiling.

Source

pub fn is_due(&self, entry: &SpoolEntry, now_unix_ms: u64) -> bool

Whether entry may be relayed again at now_unix_ms.

Why: the sweep’s only admission test. Returning false leaves the entry exactly where it is — pending, durable, and visible to the health scan — so a “not due” entry is never a dropped one. What: false past BackoffPolicy::max_attempts; otherwise the elapsed time since the last attempt (or since receipt, for a never-attempted entry) must meet BackoffPolicy::delay_after. Test: backoff_holds_off_a_freshly_spooled_entry, backoff_stops_at_max_attempts, backoff_admits_an_entry_past_its_delay.

Source

pub fn is_exhausted(&self, entry: &SpoolEntry) -> bool

Whether entry has exhausted its retries and needs an operator.

Distinguished from “not due yet” so the sweep can report the two separately — one resolves itself, the other never will.

Trait Implementations§

Source§

impl Clone for BackoffPolicy

Source§

fn clone(&self) -> BackoffPolicy

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for BackoffPolicy

Source§

impl Debug for BackoffPolicy

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for BackoffPolicy

Source§

fn default() -> Self

5 s grace, 30 s base doubling to a 1 h ceiling, giving up after 24 failures — roughly a day of retries for an entry that never lands.

Source§

impl Eq for BackoffPolicy

Source§

impl PartialEq for BackoffPolicy

Source§

fn eq(&self, other: &BackoffPolicy) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for BackoffPolicy

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more