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}