Skip to content

Implement Deadline for strategies #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ async fn action() -> Result<u64, ()> {
#[tokio::main]
async fn main() -> Result<(), ()> {
let retry_strategy = ExponentialBackoff::from_millis(10)
.map(jitter) // add jitter to delays
.take(3); // limit to 3 retries
.map(jitter) // add jitter to delays
.deadline(Duration::from_millis(500)) // stop retrying after 500ms
.take(3); // limit to 3 retries

let result = Retry::spawn(retry_strategy, action).await?;

Expand Down
13 changes: 9 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
//! ```rust,no_run
//! # extern crate tokio;
//! # extern crate tokio_retry;
//! #
//! # use std::time::Duration;
//! use tokio_retry::Retry;
//! use tokio_retry::strategy::{ExponentialBackoff, jitter};
//! use tokio_retry::strategy::{Deadline, ExponentialBackoff, jitter};
//!
//! async fn action() -> Result<u64, ()> {
//! // do some real-world stuff here...
Expand All @@ -27,13 +27,18 @@
//! # #[tokio::main]
//! # async fn main() -> Result<(), ()> {
//! let retry_strategy = ExponentialBackoff::from_millis(10)
//! .map(jitter) // add jitter to delays
//! .take(3); // limit to 3 retries
//! .map(jitter) // add jitter to delays
//! .deadline(Duration::from_millis(500)) // stop retrying after 500ms
//! .take(3); // limit to 3 retries
//!
//! let result = Retry::spawn(retry_strategy, action).await?;
//! # Ok(())
//! # }
//! ```
//!
//! NOTE: The time spent executing an action does not affect the intervals between
//! retries. Therefore, for long-running functions it's a good idea to set up a deadline,
//! to place an upper bound on the strategy execution time.

#![allow(warnings)]

Expand Down
59 changes: 59 additions & 0 deletions src/strategy/deadline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::time::Duration;
use std::time::Instant;

/// Wraps a strategy, applying deadline, after which strategy will
/// stop retrying.
pub trait Deadline: Iterator<Item = Duration> {
/// Applies a deadline for a strategy. In `max_duration` from now,
/// the strategy will stop retrying.
fn deadline(self, max_duration: Duration) -> DeadlineIterator<Self>
where
Self: Sized,
{
DeadlineIterator {
iter: self,
start: Instant::now(),
max_duration,
}
}
}

impl<I> Deadline for I where I: Iterator<Item = Duration> {}

/// A strategy wrapper with applied deadline,
/// created by [`Deadline::deadline`] function.
#[derive(Debug)]
pub struct DeadlineIterator<I> {
iter: I,
start: Instant,
max_duration: Duration,
}

impl<I: Iterator<Item = Duration>> Iterator for DeadlineIterator<I> {
type Item = Duration;

fn next(&mut self) -> Option<Self::Item> {
if self.start.elapsed() > self.max_duration {
None
} else {
self.iter.next()
}
}
}

#[cfg(test)]
mod tests {
use super::*;

use crate::strategy::FixedInterval;

#[tokio::test]
async fn returns_none_after_deadline_passes() {
let mut s = FixedInterval::from_millis(10).deadline(Duration::from_millis(50));
assert_eq!(s.next(), Some(Duration::from_millis(10)));
tokio::time::sleep(Duration::from_millis(15)).await;
assert_eq!(s.next(), Some(Duration::from_millis(10)));
tokio::time::sleep(Duration::from_millis(100)).await;
assert_eq!(s.next(), None);
}
}
2 changes: 2 additions & 0 deletions src/strategy/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod deadline;
mod exponential_backoff;
mod fibonacci_backoff;
mod fixed_interval;
mod jitter;

pub use self::deadline::Deadline;
pub use self::exponential_backoff::ExponentialBackoff;
pub use self::fibonacci_backoff::FibonacciBackoff;
pub use self::fixed_interval::FixedInterval;
Expand Down