tokio_retry2/
lib.rs

1//! This library provides extensible asynchronous retry behaviours
2//! for use with the ecosystem of [`tokio`](https://tokio.rs/) libraries.
3//!
4//! There are 4 backoff strategies:
5//! - `ExponentialBackoff`: base is considered the initial retry interval, so if defined from 500ms, the next retry will happen at 250000ms.
6//!     | attempt | delay |
7//!     |---------|-------|
8//!     | 1       | 500ms |
9//!     | 2       | 250000ms|
10//! - `ExponentialFactorBackoff`: this is a exponential backoff strategy with a base factor. What is exponentially configured is the factor, while the base retry delay is the same. So if a factor 2 is applied to an initial delay off 500ms, the attempts are as follows:
11//!     | attempt | delay |
12//!     |---------|-------|
13//!     | 1       | 500ms |
14//!     | 2       | 1000ms|
15//!     | 3       | 2000ms|
16//!     | 4       | 4000ms|
17//!
18//! - `FixedInterval`: in this backoff strategy, a fixed interval is used as constant. so if defined from 500ms, all attempts will happen at 500ms.
19//!     | attempt | delay |
20//!     |---------|-------|
21//!     | 1       | 500ms|
22//!     | 2       | 500ms|
23//!     | 3       | 500ms|
24//! - `FibonacciBackoff`: a Fibonacci backoff strategy is used. so if defined from 500ms, the next retry will happen at 500ms, and the following will be at 1000ms.
25//!     | attempt | delay |
26//!     |---------|-------|
27//!     | 1       | 500ms|
28//!     | 2       | 500ms|
29//!     | 3       | 1000ms|
30//!     | 4       | 1500ms|
31//!
32//! > All strategies can be jittered with the `jitter` feature.
33//!
34//! # Installation
35//!
36//! Add this to your `Cargo.toml`:
37//!
38//! ```toml
39//! [dependencies]
40//! tokio-retry2 = "0.5"
41//! ```
42//!
43//! # Example
44//!
45//! ```rust,no_run
46
47//! use tokio_retry2::{Retry, RetryError};
48//! use tokio_retry2::strategy::{ExponentialBackoff, MaxInterval};
49//!
50//! async fn action() -> Result<u64, RetryError<()>> {
51//!     // do some real-world stuff here...
52//!     RetryError::to_permanent(())
53//! }
54//!
55//! # #[tokio::main]
56//! # async fn main() -> Result<(), RetryError<()>> {
57//! let retry_strategy = ExponentialBackoff::from_millis(10)
58//!     .factor(1) // multiplication factor applied to deplay
59//!     .max_delay_millis(100) // set max delay between retries to 500ms
60//!     .max_interval(1000) // set max interval to 1 second for all retries
61//!     .take(3);    // limit to 3 retries
62//!
63//! let result = Retry::spawn(retry_strategy, action).await?;
64//! // First retry in 10ms, second in 100ms, third in 100ms
65
66//! # Ok(())
67//! # }
68//! ```
69//!
70//! ## Error Handling
71//!
72//! One key difference between `tokio-retry2` and `tokio-retry` is the fact that `tokio-retry2`
73//! supports early exits from the retry loop based on your error type. This allows you to pattern match
74//! your errors and define if you want to continue retrying or not, while `tokio-retry` only supported conditional `RetryIf`.
75//! The following functions are helper functions to deal with it:
76//!
77//! ```rust,no_run
78//! use tokio_retry2::{Retry, RetryError};
79//! use std::time::Duration;
80//!
81//! async fn action() -> Result<u64, RetryError<usize>> {
82//!     // do some real-world stuff here...
83//!     // get and error named `err`
84//! #   let err = std::io::ErrorKind::AddrInUse;
85//!     match err {
86//!         std::io::ErrorKind::NotFound => RetryError::to_permanent(1)?, // equivalent to return Err(RetryError::permanent(2))`;
87//!         std::io::ErrorKind::PermissionDenied => {
88//!             return Err(RetryError::permanent(2)); // equivalent to `RetryError::to_permanent(2)`
89//!         }
90//!         std::io::ErrorKind::ConnectionRefused => {
91//!             return Err(RetryError::transient(3)); // equivalent to `RetryError::to_transient(3)`
92//!         }
93//!         std::io::ErrorKind::ConnectionReset => {
94//!             return Err(RetryError::retry_after(4, Duration::from_millis(10)));
95//!             // equivalent to `RetryError::to_retry_after(4, Duration::from_millis(10))`
96//!         }
97//!         std::io::ErrorKind::ConnectionAborted =>
98//!             // equivalent to `RetryError::to_retry_after(5, Duration::from_millis(15))`
99//!             RetryError::to_retry_after(5, Duration::from_millis(15))?,
100//!         err => RetryError::to_transient(6)? // equivalent to `return Err(RetryError::transient(6))`
101//!     };
102//!     Ok(0)
103//! }
104//! ```
105//!
106//! ## Features
107//! `[jitter]`
108//! - `jitter` ranges between 50% and 150% of the strategy delay.
109//! - `jitter_range(min: f64, max: f64)` ranges between `min * Duration` and `max * Duration`.
110//!
111//! To use jitter, add this to your Cargo.toml
112//!
113//! ```toml
114//! [dependencies]
115//! tokio-retry2 = { version = "0.5", features = ["jitter"] }
116//! ```
117//!
118//! # Example
119//!
120//! ## `jitter`
121//!
122//! ```rust,no_run
123//! use tokio_retry2::Retry;
124//! use tokio_retry2::strategy::{ExponentialBackoff, jitter, MaxInterval};
125//!
126//! let retry_strategy = ExponentialBackoff::from_millis(10)
127//!    .max_interval(10000) // set max interval to 10 seconds
128//!    .map(jitter) // add jitter to the retry interval
129//!    .take(3);    // limit to 3 retries
130//!````
131//!
132//! ## `jitter_range`
133//!
134//! ```rust,no_run
135//! use tokio_retry2::Retry;
136//! use tokio_retry2::strategy::{ExponentialFactorBackoff, jitter_range, MaxInterval};
137//!
138//! let retry_strategy = ExponentialFactorBackoff::from_millis(10, 2.)
139//!    .max_interval(10000) // set max interval to 10 seconds
140//!    .map(jitter_range(0.5, 1.2)) // add jitter ranging between 50% and 120% to the retry interval
141//!    .take(3);    // limit to 3 retries
142//!````
143//!
144//! ### NOTE:
145//! The time spent executing an action does not affect the intervals between
146//! retries. Therefore, for long-running functions it's a good idea to set up a deadline,
147//! to place an upper bound on the strategy execution time.
148
149#![allow(warnings)]
150
151mod action;
152mod condition;
153pub(crate) mod error;
154mod future;
155mod notify;
156/// Assorted retry strategies including fixed interval and exponential back-off.
157pub mod strategy;
158
159pub use action::Action;
160pub use condition::Condition;
161pub use error::{Error as RetryError, MapErr};
162pub use future::{Retry, RetryIf};