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.