Skip to main content

Backoff

Struct Backoff 

Source
pub struct Backoff { /* private fields */ }
Expand description

The retry state of one loop.

A loop holds one of these, tells it when an attempt succeeded or failed, and asks it to wait. Nothing else in the loop needs to know about multiplying, ceilings or slicing.

§Examples

use std::time::Duration;
use graceful_worker::Backoff;

let mut backoff = Backoff::new();
assert_eq!(backoff.delay(), Duration::from_secs(5));

backoff.failed();
assert_eq!(backoff.delay(), Duration::from_secs(10));
backoff.failed();
assert_eq!(backoff.delay(), Duration::from_secs(20));

// Any success puts it straight back to the start.
backoff.succeeded();
assert_eq!(backoff.delay(), Duration::from_secs(5));
assert_eq!(backoff.attempt(), 0);

A schedule of your own:

use std::time::Duration;
use graceful_worker::Backoff;

let backoff = Backoff::new()
    .with_initial_delay(Duration::from_millis(100))
    .with_max_delay(Duration::from_secs(30))
    .with_slice(Duration::from_secs(5))
    .with_factor(3);

assert_eq!(backoff.delay(), Duration::from_millis(100));

Implementations§

Source§

impl Backoff

Source

pub const fn new() -> Self

A fresh backoff on the default schedule.

Source

pub const fn with_initial_delay(self, initial: Duration) -> Self

Set the first delay, and reset to it.

Clamped to the ceiling, so an initial delay longer than the maximum is the maximum rather than a schedule that counts downwards.

Source

pub const fn with_max_delay(self, max: Duration) -> Self

Set the ceiling.

Source

pub const fn with_slice(self, slice: Duration) -> Self

Set the longest single sleep Backoff::wait performs.

This is the worst case for how long a stop goes unnoticed during a wait, so it should be comfortably shorter than the platform’s grace period. Duration::ZERO disables slicing, which restores the behaviour of every other backoff crate — including its drawback.

Source

pub const fn with_factor(self, factor: u32) -> Self

Set the multiplier applied after each failure.

A factor of 1 is a constant delay. Zero is treated as 1, because a backoff that multiplies by zero would retry instantly forever.

Source

pub const fn delay(&self) -> Duration

How long to wait before the next attempt.

Source

pub const fn attempt(&self) -> u32

How many consecutive failures there have been.

Useful as a dimension on a retry metric.

Source

pub const fn is_retrying(&self) -> bool

Whether anything has failed since the last success.

A loop uses this to decide whether an empty queue is unremarkable or worth a log line.

Source

pub const fn max_delay(&self) -> Duration

The ceiling this backoff will not exceed.

Source

pub const fn failed(&mut self) -> Duration

Record a failure: multiply the delay, up to the ceiling.

Returns the delay that was in force for this failure, which is what a metric should record — not the multiplied value the next one will use.

Source

pub const fn succeeded(&mut self)

Record a success: back to the initial delay, attempt count zero.

Any success resets it, not just a run of them.

Source

pub const fn sleep_slice(&self, remaining: Duration) -> Duration

The slice to sleep for, given how much of a delay is left.

Never zero while remaining is non-zero, which is what stops Backoff::wait spinning.

§Examples
use std::time::Duration;
use graceful_worker::Backoff;

let backoff = Backoff::new();

// A short remainder is slept in one go.
assert_eq!(backoff.sleep_slice(Duration::from_secs(3)), Duration::from_secs(3));
// A long one is sliced, so shutdown stays responsive.
assert_eq!(backoff.sleep_slice(Duration::from_secs(900)), Duration::from_secs(60));
Source

pub async fn wait(&self, watcher: &Watcher) -> bool

Wait out the current delay, in slices, unless a stop arrives first.

Returns true if the whole delay elapsed, false if it was cut short — in which case the loop should stop rather than retry.

This is the method the crate exists for. See the module documentation.

§Examples

The usual loop shape. Marked no_run because running it would do exactly what it says: wait five real seconds.

use graceful_worker::{Backoff, Shutdown};

let shutdown = Shutdown::new();
let watcher = shutdown.watcher();
let mut backoff = Backoff::new();

while watcher.is_running() {
    let worked = false; // ... do a unit of work ...
    if worked {
        backoff.succeeded();
    } else {
        backoff.failed();
        if !backoff.wait(&watcher).await {
            break; // asked to stop mid-wait
        }
    }
}

Trait Implementations§

Source§

impl Clone for Backoff

Source§

fn clone(&self) -> Backoff

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 Debug for Backoff

Source§

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

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

impl Default for Backoff

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Eq for Backoff

Source§

impl PartialEq for Backoff

Source§

fn eq(&self, other: &Backoff) -> 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 Backoff

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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> 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 = Infallible

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