Crate backon

Source
Expand description

Build Status Latest Version

BackON

Make retry like a built-in feature provided by Rust.

  • Simple: Just like a built-in feature: your_fn.retry(ExponentialBuilder::default()).await.
  • Flexible: Supports both blocking and async functions.
  • Powerful: Allows control over retry behavior such as when and notify.
  • Customizable: Supports custom retry strategies like exponential, constant, etc.

§Backoff

Retry in BackON requires a backoff strategy. BackON will accept a BackoffBuilder which will generate a new Backoff for each retry. It also accepts any object that implements Backoff. You can therefore easily implement your own custom backoff strategy.

BackON provides several backoff implementations with reasonable defaults:

§Sleep

Retry in BackON requires an implementation for sleeping, such an implementation is called a Sleeper, it will implement Sleeper or BlockingSleeper depending on if it is going to be used in an asynchronous context.

§Default Sleeper

Currently, BackON has 3 built-in Sleeper implementations for different environments, they are gated under their own features, which are enabled by default:

SleeperfeatureEnvironmentAsynchronous
TokioSleepertokio-sleepnon-wasm32Yes
[GlooTimersSleep]gloo-timers-sleepwasm32Yes
[FutureTimerSleep]future-timer-sleepwasm/non-wasmYes
[EmbassySleep]embassy-sleepno_stdYes
StdSleeperstd-blocking-sleepstdNo

§Custom Sleeper

If you do not want to use the built-in Sleeper, you CAN provide a custom implementation, let’s implement an asynchronous dummy Sleeper that does not sleep at all. You will find it pretty similar when you implement a blocking one.

use std::time::Duration;
use backon::Sleeper;

/// A dummy `Sleeper` impl that prints then becomes ready!
struct DummySleeper;

impl Sleeper for DummySleeper {
    type Sleep = std::future::Ready<()>;

    fn sleep(&self, dur: Duration) -> Self::Sleep {
        println!("Hello from DummySleeper!");
        std::future::ready(())
    }
}

§The empty Sleeper

If neither feature is enabled nor a custom implementation is provided, BackON will fallback to the empty sleeper, in which case, a compile-time error that PleaseEnableAFeatureOrProvideACustomSleeper needs to implement Sleeper or BlockingSleeper will be raised to remind you to choose or bring a real Sleeper implementation.

§Retry

For additional examples, please visit docs::examples.

§Retry an async function

use anyhow::Result;
use backon::ExponentialBuilder;
use backon::Retryable;
use core::time::Duration;

async fn fetch() -> Result<String> {
    Ok("hello, world!".to_string())
}

#[tokio::main]
async fn main() -> Result<()> {
    let content = fetch
        // Retry with exponential backoff
        .retry(ExponentialBuilder::default())
        // Sleep implementation, default to tokio::time::sleep if `tokio-sleep` has been enabled.
        .sleep(tokio::time::sleep)
        // When to retry
        .when(|e| e.to_string() == "EOF")
        // Notify when retrying
        .notify(|err: &anyhow::Error, dur: Duration| {
            println!("retrying {:?} after {:?}", err, dur);
        })
        .await?;
    println!("fetch succeeded: {}", content);

    Ok(())
}

§Retry a blocking function

use anyhow::Result;
use backon::BlockingRetryable;
use backon::ExponentialBuilder;
use core::time::Duration;

fn fetch() -> Result<String> {
    Ok("hello, world!".to_string())
}

fn main() -> Result<()> {
    let content = fetch
        // Retry with exponential backoff
        .retry(ExponentialBuilder::default())
        // Sleep implementation, default to std::thread::sleep if `std-blocking-sleep` has been enabled.
        .sleep(std::thread::sleep)
        // When to retry
        .when(|e| e.to_string() == "EOF")
        // Notify when retrying
        .notify(|err: &anyhow::Error, dur: Duration| {
            println!("retrying {:?} after {:?}", err, dur);
        })
        .call()?;
    println!("fetch succeeded: {}", content);

    Ok(())
}

Re-exports§

pub use constant::ConstantBackoff;
pub use fibonacci::FibonacciBackoff;
pub use exponential::ExponentialBackoff;

Modules§

docsdocsrs
Docs for the backon crate, like examples.

Structs§

BlockingRetry
Retry structure generated by BlockingRetryable.
BlockingRetryWithContext
Retry structure generated by BlockingRetryableWithContext.
ConstantBuilder
ConstantBuilder is used to create a [ConstantBackoff], providing a steady delay with a fixed number of retries.
EmbassySleeperembassy-sleep
A no_std async sleeper based on the embassy framework (https://embassy.dev)
ExponentialBuilder
ExponentialBuilder is used to construct an [ExponentialBackoff] that offers delays with exponential retries.
FibonacciBuilder
FibonacciBuilder is used to build a [FibonacciBackoff] which offers a delay with Fibonacci-based retries.
Retry
Struct generated by Retryable.
RetryWithContext
Retry struct generated by RetryableWithContext.
StdSleeperstd-blocking-sleep
The implementation of StdSleeper uses std::thread::sleep.
TokioSleeperNon-WebAssembly and tokio-sleep
The default implementation of Sleeper uses tokio::time::sleep.

Traits§

Backoff
Backoff is an Iterator that returns Duration.
BackoffBuilder
BackoffBuilder is utilized to construct a new backoff.
BlockingRetryable
BlockingRetryable adds retry support for blocking functions.
BlockingRetryableWithContext
BlockingRetryableWithContext adds retry support for blocking functions.
BlockingSleeper
A sleeper is used sleep for a specified duration.
Retryable
Retryable will add retry support for functions that produce futures with results.
RetryableWithContext
RetryableWithContext adds retry support for functions that produce futures with results and context.
Sleeper
A sleeper is used to generate a future that completes after a specified duration.

Type Aliases§

DefaultBlockingSleeper
The default implementation of Sleeper while feature std-blocking-sleep enabled.
DefaultSleeper
The default implementation of Sleeper while feature tokio-sleep enabled.