Skip to main content

do_over/
timeout.rs

1//! Timeout policy for time-bounded operations.
2//!
3//! The timeout policy ensures operations complete within a specified duration,
4//! preventing indefinite hangs.
5//!
6//! # Examples
7//!
8//! ```rust
9//! use do_over::{policy::Policy, timeout::TimeoutPolicy, error::DoOverError};
10//! use std::time::Duration;
11//!
12//! # async fn example() -> Result<(), DoOverError<std::io::Error>> {
13//! let policy = TimeoutPolicy::new(Duration::from_secs(5));
14//!
15//! match policy.execute(|| async {
16//!     // Operation that might hang
17//!     Ok::<_, DoOverError<std::io::Error>>("completed")
18//! }).await {
19//!     Ok(result) => println!("Success: {}", result),
20//!     Err(DoOverError::Timeout) => println!("Operation timed out"),
21//!     Err(e) => println!("Error: {:?}", e),
22//! }
23//! # Ok(())
24//! # }
25//! ```
26
27use std::time::Duration;
28use tokio::time;
29use crate::policy::Policy;
30use crate::error::DoOverError;
31
32/// A policy that enforces a maximum duration for operations.
33///
34/// If the operation doesn't complete within the timeout, it is cancelled
35/// and [`DoOverError::Timeout`] is returned.
36///
37/// # Examples
38///
39/// ```rust
40/// use do_over::{policy::Policy, timeout::TimeoutPolicy, error::DoOverError};
41/// use std::time::Duration;
42///
43/// # async fn example() {
44/// let policy = TimeoutPolicy::new(Duration::from_secs(10));
45///
46/// let result: Result<String, DoOverError<String>> = policy.execute(|| async {
47///     // Long-running operation
48///     Ok("done".to_string())
49/// }).await;
50/// # }
51/// ```
52#[derive(Clone)]
53pub struct TimeoutPolicy {
54    timeout: Duration,
55}
56
57impl TimeoutPolicy {
58    /// Create a new timeout policy.
59    ///
60    /// # Arguments
61    ///
62    /// * `timeout` - Maximum duration to wait for the operation
63    ///
64    /// # Examples
65    ///
66    /// ```rust
67    /// use do_over::timeout::TimeoutPolicy;
68    /// use std::time::Duration;
69    ///
70    /// // 5 second timeout
71    /// let policy = TimeoutPolicy::new(Duration::from_secs(5));
72    /// ```
73    pub fn new(timeout: Duration) -> Self {
74        Self { timeout }
75    }
76}
77
78#[async_trait::async_trait]
79impl<E> Policy<DoOverError<E>> for TimeoutPolicy
80where
81    E: Send + Sync,
82{
83    async fn execute<F, Fut, T>(&self, f: F) -> Result<T, DoOverError<E>>
84    where
85        F: Fn() -> Fut + Send + Sync,
86        Fut: std::future::Future<Output = Result<T, DoOverError<E>>> + Send,
87        T: Send,
88    {
89        match time::timeout(self.timeout, f()).await {
90            Ok(r) => r,
91            Err(_) => Err(DoOverError::Timeout),
92        }
93    }
94}