Skip to main content

revoke_resilience/
timeout.rs

1use crate::error::{ResilienceError, Result};
2use std::time::Duration;
3use tokio::time::timeout as tokio_timeout;
4use tracing::{debug, warn};
5
6/// 超时处理器
7#[derive(Debug, Clone)]
8pub struct Timeout {
9    duration: Duration,
10    name: Option<String>,
11}
12
13impl Timeout {
14    /// 创建新的超时处理器
15    pub fn new(duration: Duration) -> Self {
16        Self {
17            duration,
18            name: None,
19        }
20    }
21
22    /// 设置名称
23    pub fn with_name(mut self, name: impl Into<String>) -> Self {
24        self.name = Some(name.into());
25        self
26    }
27
28    /// 执行带超时的操作
29    pub async fn execute<F, T>(&self, future: F) -> Result<T>
30    where
31        F: std::future::Future<Output = Result<T>>,
32    {
33        let name = self.name.as_deref().unwrap_or("未命名");
34        
35        debug!("开始执行操作 '{}', 超时: {:?}", name, self.duration);
36        
37        match tokio_timeout(self.duration, future).await {
38            Ok(result) => {
39                debug!("操作 '{}' 在超时前完成", name);
40                result
41            }
42            Err(_) => {
43                warn!("操作 '{}' 超时 ({:?})", name, self.duration);
44                Err(ResilienceError::Timeout(format!(
45                    "操作 '{}' 在 {:?} 后超时",
46                    name, self.duration
47                )))
48            }
49        }
50    }
51
52    /// 执行带超时的操作,返回 Option
53    pub async fn execute_optional<F, T>(&self, future: F) -> Option<T>
54    where
55        F: std::future::Future<Output = T>,
56    {
57        let name = self.name.as_deref().unwrap_or("未命名");
58        
59        debug!("开始执行操作 '{}', 超时: {:?}", name, self.duration);
60        
61        match tokio_timeout(self.duration, future).await {
62            Ok(result) => {
63                debug!("操作 '{}' 在超时前完成", name);
64                Some(result)
65            }
66            Err(_) => {
67                warn!("操作 '{}' 超时 ({:?})", name, self.duration);
68                None
69            }
70        }
71    }
72}
73
74/// 快速超时函数
75pub async fn with_timeout<F, T>(duration: Duration, future: F) -> Result<T>
76where
77    F: std::future::Future<Output = Result<T>>,
78{
79    Timeout::new(duration).execute(future).await
80}
81
82/// 快速超时函数(返回 Option)
83pub async fn with_timeout_optional<F, T>(duration: Duration, future: F) -> Option<T>
84where
85    F: std::future::Future<Output = T>,
86{
87    Timeout::new(duration).execute_optional(future).await
88}
89
90/// 动态超时管理器
91#[derive(Debug)]
92pub struct DynamicTimeout {
93    base_duration: Duration,
94    min_duration: Duration,
95    max_duration: Duration,
96    adjustment_factor: f64,
97    current_duration: parking_lot::RwLock<Duration>,
98    success_count: std::sync::atomic::AtomicU32,
99    timeout_count: std::sync::atomic::AtomicU32,
100}
101
102impl DynamicTimeout {
103    /// 创建新的动态超时管理器
104    pub fn new(base_duration: Duration) -> Self {
105        Self {
106            base_duration,
107            min_duration: Duration::from_millis(100),
108            max_duration: Duration::from_secs(300),
109            adjustment_factor: 1.5,
110            current_duration: parking_lot::RwLock::new(base_duration),
111            success_count: std::sync::atomic::AtomicU32::new(0),
112            timeout_count: std::sync::atomic::AtomicU32::new(0),
113        }
114    }
115
116    /// 设置最小超时
117    pub fn with_min_duration(mut self, duration: Duration) -> Self {
118        self.min_duration = duration;
119        self
120    }
121
122    /// 设置最大超时
123    pub fn with_max_duration(mut self, duration: Duration) -> Self {
124        self.max_duration = duration;
125        self
126    }
127
128    /// 设置调整因子
129    pub fn with_adjustment_factor(mut self, factor: f64) -> Self {
130        self.adjustment_factor = factor;
131        self
132    }
133
134    /// 获取当前超时时间
135    pub fn current_duration(&self) -> Duration {
136        *self.current_duration.read()
137    }
138
139    /// 执行带动态超时的操作
140    pub async fn execute<F, T>(&self, future: F) -> Result<T>
141    where
142        F: std::future::Future<Output = Result<T>>,
143    {
144        let current = self.current_duration();
145        let timeout = Timeout::new(current);
146        
147        match timeout.execute(future).await {
148            Ok(result) => {
149                self.record_success();
150                Ok(result)
151            }
152            Err(ResilienceError::Timeout(_)) => {
153                self.record_timeout();
154                Err(ResilienceError::Timeout(format!(
155                    "动态超时: {:?}",
156                    current
157                )))
158            }
159            Err(e) => Err(e),
160        }
161    }
162
163    /// 记录成功
164    fn record_success(&self) {
165        use std::sync::atomic::Ordering;
166        
167        let success_count = self.success_count.fetch_add(1, Ordering::Relaxed);
168        let timeout_count = self.timeout_count.load(Ordering::Relaxed);
169        
170        // 每 10 次成功后调整
171        if success_count % 10 == 0 && timeout_count == 0 {
172            let mut current = self.current_duration.write();
173            let new_duration = current.as_millis() as f64 / self.adjustment_factor;
174            let new_duration = Duration::from_millis(new_duration as u64).max(self.min_duration);
175            
176            if new_duration != *current {
177                debug!("减少超时时间: {:?} -> {:?}", current, new_duration);
178                *current = new_duration;
179                self.timeout_count.store(0, Ordering::Relaxed);
180            }
181        }
182    }
183
184    /// 记录超时
185    fn record_timeout(&self) {
186        use std::sync::atomic::Ordering;
187        
188        let timeout_count = self.timeout_count.fetch_add(1, Ordering::Relaxed);
189        
190        // 连续 3 次超时后调整
191        if timeout_count >= 2 {
192            let mut current = self.current_duration.write();
193            let new_duration = current.as_millis() as f64 * self.adjustment_factor;
194            let new_duration = Duration::from_millis(new_duration as u64).min(self.max_duration);
195            
196            if new_duration != *current {
197                debug!("增加超时时间: {:?} -> {:?}", current, new_duration);
198                *current = new_duration;
199                self.timeout_count.store(0, Ordering::Relaxed);
200                self.success_count.store(0, Ordering::Relaxed);
201            }
202        }
203    }
204
205    /// 重置到基础超时
206    pub fn reset(&self) {
207        use std::sync::atomic::Ordering;
208        
209        *self.current_duration.write() = self.base_duration;
210        self.success_count.store(0, Ordering::Relaxed);
211        self.timeout_count.store(0, Ordering::Relaxed);
212        debug!("超时重置到基础值: {:?}", self.base_duration);
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219    use tokio::time::sleep;
220
221    #[tokio::test]
222    async fn test_timeout_success() {
223        let timeout = Timeout::new(Duration::from_millis(100));
224        
225        let result = timeout.execute(async {
226            sleep(Duration::from_millis(50)).await;
227            Ok(42)
228        }).await;
229        
230        assert_eq!(result.unwrap(), 42);
231    }
232
233    #[tokio::test]
234    async fn test_timeout_failure() {
235        let timeout = Timeout::new(Duration::from_millis(50));
236        
237        let result = timeout.execute(async {
238            sleep(Duration::from_millis(100)).await;
239            Ok(42)
240        }).await;
241        
242        assert!(matches!(result, Err(ResilienceError::Timeout(_))));
243    }
244
245    #[tokio::test]
246    async fn test_with_timeout() {
247        let result = with_timeout(Duration::from_millis(100), async {
248            sleep(Duration::from_millis(50)).await;
249            Ok("success")
250        }).await;
251        
252        assert_eq!(result.unwrap(), "success");
253    }
254
255    #[tokio::test]
256    async fn test_with_timeout_optional() {
257        let result = with_timeout_optional(Duration::from_millis(100), async {
258            sleep(Duration::from_millis(50)).await;
259            42
260        }).await;
261        
262        assert_eq!(result, Some(42));
263        
264        let result = with_timeout_optional(Duration::from_millis(50), async {
265            sleep(Duration::from_millis(100)).await;
266            42
267        }).await;
268        
269        assert_eq!(result, None);
270    }
271
272    #[tokio::test]
273    async fn test_dynamic_timeout() {
274        let dynamic = DynamicTimeout::new(Duration::from_millis(100))
275            .with_min_duration(Duration::from_millis(50))
276            .with_max_duration(Duration::from_millis(200))
277            .with_adjustment_factor(2.0);
278        
279        // 初始超时应该是 100ms
280        assert_eq!(dynamic.current_duration(), Duration::from_millis(100));
281        
282        // 记录几次超时
283        for _ in 0..3 {
284            let _ = dynamic.execute(async {
285                sleep(Duration::from_millis(150)).await;
286                Ok(())
287            }).await;
288        }
289        
290        // 超时时间应该增加
291        assert!(dynamic.current_duration() > Duration::from_millis(100));
292        
293        // 重置
294        dynamic.reset();
295        assert_eq!(dynamic.current_duration(), Duration::from_millis(100));
296    }
297}