revoke_resilience/
timeout.rs1use crate::error::{ResilienceError, Result};
2use std::time::Duration;
3use tokio::time::timeout as tokio_timeout;
4use tracing::{debug, warn};
5
6#[derive(Debug, Clone)]
8pub struct Timeout {
9 duration: Duration,
10 name: Option<String>,
11}
12
13impl Timeout {
14 pub fn new(duration: Duration) -> Self {
16 Self {
17 duration,
18 name: None,
19 }
20 }
21
22 pub fn with_name(mut self, name: impl Into<String>) -> Self {
24 self.name = Some(name.into());
25 self
26 }
27
28 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 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
74pub 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
82pub 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#[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 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 pub fn with_min_duration(mut self, duration: Duration) -> Self {
118 self.min_duration = duration;
119 self
120 }
121
122 pub fn with_max_duration(mut self, duration: Duration) -> Self {
124 self.max_duration = duration;
125 self
126 }
127
128 pub fn with_adjustment_factor(mut self, factor: f64) -> Self {
130 self.adjustment_factor = factor;
131 self
132 }
133
134 pub fn current_duration(&self) -> Duration {
136 *self.current_duration.read()
137 }
138
139 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 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 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 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 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 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 assert_eq!(dynamic.current_duration(), Duration::from_millis(100));
281
282 for _ in 0..3 {
284 let _ = dynamic.execute(async {
285 sleep(Duration::from_millis(150)).await;
286 Ok(())
287 }).await;
288 }
289
290 assert!(dynamic.current_duration() > Duration::from_millis(100));
292
293 dynamic.reset();
295 assert_eq!(dynamic.current_duration(), Duration::from_millis(100));
296 }
297}