[−][src]Crate tryhard
Easily retry futures.
Example usage
// some async function that can fail async fn read_file(path: &str) -> Result<String, std::io::Error> { // ... } let contents = tryhard::retry_fn(|| read_file("Cargo.toml")) // retry at most 10 times .retries(10) .await?; assert!(contents.contains("tryhard"));
You can also customize which backoff strategy to use and what the max retry delay should be:
use std::time::Duration; let contents = tryhard::retry_fn(|| read_file("Cargo.toml")) .retries(10) .exponential_backoff(Duration::from_millis(10)) .max_delay(Duration::from_secs(1)) .await?; assert!(contents.contains("tryhard"));
How many times will my future run?
The future is always run at least once, so if you do .retries(0)
your future will run once.
If you do .retries(10)
and your future always fails it'll run 11 times.
Why do you require a closure?
Due to how futures work in Rust you're not able to retry a bare F where F: Future
. A future
can possibly fail at any point in its execution and might be in an inconsistent state after the
failing. Therefore retrying requires making a fresh future for each attempt.
This means you cannot move values into the closure that produces the futures. You'll have to clone instead:
async fn future_with_owned_data(data: Vec<u8>) -> Result<(), std::io::Error> { // ... } let data: Vec<u8> = vec![1, 2, 3]; tryhard::retry_fn(|| { // We need to clone `data` here. Otherwise we would have to move `data` into the closure. // `move` closures can only be called once (they only implement `FnOnce`) // and therefore cannot be used to create more than one future. let data = data.clone(); async { future_with_owned_data(data).await } }).retries(10).await?;
Be careful what you retry
This library is meant to make it straight forward to retry simple futures, such as sending a single request to some service that occationally fails. If you have some complex operation that consists of multiple futures each of which can fail, this library might be not appropriate. You risk repeating the same operation more than once because some later operation keeps failing.
Tokio only for now
This library currently expects to be used from within a tokio runtime. That is because it makes use of async timers. Feel free to open an issue if you need support for other runtimes.
By default it uses Tokio 0.3. You can switch to Tokio 0.2 by disabling default features and
enabling the tokio-02
feature:
tryhard = { version = "your-version", default-features = false, features = ["tokio-02"] }
Note that enabling both Tokio 0.3 and 0.2 will cause a compilation error.
Modules
backoff_strategies | The types of backoff strategies that are supported |
Structs
RetryFn | A type that produces retryable futures. |
RetryFuture | A retryable future. |
Enums
RetryPolicy | What to do when a future returns an error. Used with |
Traits
OnRetry | Trait allowing you to run some future when a retry occurs. Could for example to be used for logging or other kinds of telemetry. |
Functions
retry_fn | Create a |