Crate backoff_futures

Source
Expand description

An add-on to std::future::Future that makes it easy to introduce a retry mechanism with a backoff for functions that produce failible futures, i.e. futures where the Output type is some Result<T, backoff::Error<E>>. The backoff::Error wrapper is necessary so as to distinguish errors that are considered transient, and thus make it likely that a future attempt at producing and blocking on the same future could just as well succeed (e.g. the HTTP 503 Service Unavailable error), and errors that are considered permanent, where no future attempts are presumed to have a chance to succeed (e.g. the HTTP 404 Not Found error).

The extension trait integrates with the backoff crate and expects a backoff::backoff::Backoff value to describe the various properties of the retry & backoff mechanism to be used.

fn isahc_error_to_backoff(err: isahc::Error) -> backoff::Error<isahc::Error> {
    match err {
        isahc::Error::Aborted | isahc::Error::Io(_) | isahc::Error::Timeout =>
            backoff::Error::Transient(err),
        _ =>
            backoff::Error::Permanent(err)
    }
}

async fn get_example_contents() -> Result<String, backoff::Error<isahc::Error>> {
    use isahc::ResponseExt;

    let mut response = isahc::get_async("https://example.org")
        .await
        .map_err(isahc_error_to_backoff)?;

    response
        .text_async()
        .await
        .map_err(|err: std::io::Error| backoff::Error::Transient(isahc::Error::Io(err)))
}

async fn get_example_contents_with_retry() -> Result<String, isahc::Error> {
    use backoff_futures::BackoffExt;

    let mut backoff = backoff::ExponentialBackoff::default();
    get_example_contents.with_backoff(&mut backoff)
        .await
        .map_err(|err| match err {
            backoff::Error::Transient(err) | backoff::Error::Permanent(err) => err
        })
}

See BackoffExt::with_backoff for more details.

Traitsยง