Crate retry_block
source · [−]Expand description
retry-block
provides utilities to retry operations that may fail with configurable backoff behavior.
Usage
Retry an operation using the corresponding retry
macro or retry_fn
function. The macro
accepts an iterator over Duration
s and a block that returns a Result
(or OperationResult
;
see below). The iterator is used to determine how long to wait after each unsuccessful try and
how many times to try before giving up and returning Result::Err
. The block determines either
the final successful value, or an error value, which can either be returned immediately or used
to indicate that the operation should be retried.
Any type that implements IntoIterator<Item = Duration>
can be used to determine retry behavior,
though a few useful implementations are provided in the delay
module, including a fixed delay
and exponential back-off.
The Iterator
API can be used to limit or modify the delay strategy. For example, to limit the
number of retries to 1:
let mut collection = vec![1, 2, 3].into_iter();
let result = retry!(Fixed::new(Duration::from_millis(100)).take(1), {
match collection.next() {
Some(n) if n == 3 => Ok("n is 3!"),
Some(_) => Err("n must be 3!"),
None => Err("n was never 3!"),
}
});
assert!(result.is_err());
The RetryConfig struct can be used to retry an operation with a serializable retry config that specifies an amount of retries and a random backoff interval.
let config = RetryConfig {
count: 1,
min_backoff: 100,
max_backoff: 300,
};
let mut collection = vec![1, 2, 3].into_iter();
let result = retry!(config, {
match collection.next() {
Some(n) if n == 3 => Ok("n is 3!"),
Some(_) => Err("n must be 3!"),
None => Err("n was never 3!"),
}
});
assert!(result.is_err());
Random jitter is applied by default to any delay strategy, but you can make it fixed using exact
or add random jitter to any delay strategy using the jitter
function:
let mut collection = vec![1, 2, 3].into_iter();
let result = retry_fn(Exponential::exact(Duration::from_millis(10)).map(jitter).take(3), || {
match collection.next() {
Some(n) if n == 3 => Ok("n is 3!"),
Some(_) => Err("n must be 3!"),
None => Err("n was never 3!"),
}
});
assert!(result.is_ok());
To deal with fatal errors, return retry_block::OperationResult
, which is like std’s Result
, but
with a third case to distinguish between errors that should cause a retry and errors that
should immediately return, halting retry behavior. (Internally, OperationResult
is always
used, and closures passed to retry
that return plain Result
are converted into
OperationResult
.)
let mut collection = vec![1, 2].into_iter();
let value = retry!(Fixed::new(Duration::from_millis(1)), {
match collection.next() {
Some(n) if n == 2 => OperationResult::Ok(n),
Some(_) => OperationResult::Retry("not 2"),
None => OperationResult::Err("not found"),
}
}).unwrap();
assert_eq!(value, 2);
Features
random
: offer some random delay utilities (on by default)config
: offer serializable retry config (on by default)future
: offer asynchronous retry mechanisms (on by default)
Re-exports
pub use future::*;
Modules
Different types of delay for retryable operations.
Asychronous versions of the common retry functions
Tools for persistent retries that save the retry status to be continued on a restart
Macros
Retry a block with tokio::time::sleep
Retry an operation forever with exponential delay until it succeeds
Retry a block with std::thread::sleep
Retry an operation forever with exponential delay until it succeeds
Structs
A serializable retry configuration for a random range and finite retry count
Enums
Functions
Retry the given operation until it succeeds, or until the given Duration
iterator ends.