[−][src]Crate retry
Crate retry provides utilities for retrying operations that can fail.
Usage
Retry an operation using the retry function. retry accepts an iterator over Durations and
a closure 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 closure 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 Iterator<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.
let mut collection = vec![1, 2, 3].into_iter(); let result = retry(Fixed::from_millis(100), || { 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());
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::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());
To apply random jitter to any delay strategy, the jitter function can be used in combination
with the Iterator API:
let mut collection = vec![1, 2, 3].into_iter(); let result = retry(Exponential::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::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.)
use retry::OperationResult; let mut collection = vec![1, 2].into_iter(); let value = retry(Fixed::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);
If your operation needs to know how many times it's been tried, use the retry_with_index
function. This works the same as retry, but passes the number of the current try to the
closure as an argument.
let mut collection = vec![1, 2, 3, 4, 5].into_iter(); let result = retry_with_index(Fixed::from_millis(100), |current_try| { if current_try > 3 { return OperationResult::Err("did not succeed within 3 tries"); } match collection.next() { Some(n) if n == 5 => OperationResult::Ok("n is 5!"), Some(_) => OperationResult::Retry("n must be 5!"), None => OperationResult::Retry("n was never 5!"), } }); assert!(result.is_err());
Features
random: offer some random delay utilities (on by default)
Modules
| delay | Different types of delay for retryable operations. |
Enums
| Error | An error with a retryable operation. |
| OperationResult | A result that represents either success, retryable failure, or immediately-returning failure. |
Functions
| retry | Retry the given operation synchronously until it succeeds, or until the given |
| retry_with_index | Retry the given operation synchronously until it succeeds, or until the given |