AirLibrary/Resilience/
Timeout.rs1use std::time::{Duration, Instant};
13
14use crate::dev_log;
15
16pub struct TimeoutManager {
18 global_deadline:Option<Instant>,
19
20 operation_timeout:Duration,
21}
22
23impl TimeoutManager {
24 pub fn new(operation_timeout:Duration) -> Self { Self { global_deadline:None, operation_timeout } }
26
27 pub fn with_deadline(global_deadline:Instant, operation_timeout:Duration) -> Self {
29 Self { global_deadline:Some(global_deadline), operation_timeout }
30 }
31
32 pub fn ValidateTimeout(timeout:Duration) -> Result<(), String> {
34 if timeout.is_zero() {
35 return Err("Timeout must be greater than 0".to_string());
36 }
37
38 if timeout.as_secs() > 3600 {
39 return Err("Timeout cannot exceed 1 hour".to_string());
40 }
41
42 Ok(())
43 }
44
45 pub fn ValidateTimeoutResult(timeout:Duration) -> Result<Duration, String> {
47 if timeout.is_zero() {
48 return Err("Timeout must be greater than 0".to_string());
49 }
50
51 if timeout.as_secs() > 3600 {
52 return Err("Timeout cannot exceed 1 hour".to_string());
53 }
54
55 Ok(timeout)
56 }
57
58 pub fn remaining(&self) -> Option<Duration> {
60 self.global_deadline.map(|deadline| {
61 deadline
62 .checked_duration_since(Instant::now())
63 .unwrap_or(Duration::from_secs(0))
64 })
65 }
66
67 pub fn Remaining(&self) -> Option<Duration> {
69 std::panic::catch_unwind(|| self.remaining()).unwrap_or_else(|e| {
70 dev_log!("resilience", "error: [TimeoutManager] Panic in Remaining: {:?}", e);
71
72 None
73 })
74 }
75
76 pub fn effective_timeout(&self) -> Duration {
78 match self.remaining() {
79 Some(remaining) => self.operation_timeout.min(remaining),
80
81 None => self.operation_timeout,
82 }
83 }
84
85 pub fn EffectiveTimeout(&self) -> Duration {
87 std::panic::catch_unwind(|| {
88 let timeout = self.effective_timeout();
89
90 match Self::ValidateTimeoutResult(timeout) {
91 Ok(valid_timeout) => valid_timeout,
92 Err(_) => Duration::from_secs(30),
93 }
94 })
95 .unwrap_or_else(|e| {
96 dev_log!("resilience", "error: [TimeoutManager] Panic in EffectiveTimeout: {:?}", e);
97
98 Duration::from_secs(30)
99 })
100 }
101
102 pub fn is_exceeded(&self) -> bool { self.global_deadline.map_or(false, |deadline| Instant::now() >= deadline) }
104
105 pub fn IsExceeded(&self) -> bool {
107 std::panic::catch_unwind(|| self.is_exceeded()).unwrap_or_else(|e| {
108 dev_log!("resilience", "error: [TimeoutManager] Panic in IsExceeded: {:?}", e);
109
110 true
111 })
112 }
113
114 pub fn GetGlobalDeadline(&self) -> Option<Instant> { self.global_deadline }
115
116 pub fn GetOperationTimeout(&self) -> Duration { self.operation_timeout }
117}