futu_net/
reconnect.rs

1use std::time::Duration;
2
3/// 重连策略:指数退避
4///
5/// 每次重连失败后,等待时间翻倍,直到达到最大等待时间。
6/// 成功连接后重置。
7#[derive(Debug, Clone)]
8pub struct ReconnectPolicy {
9    base_delay: Duration,
10    max_delay: Duration,
11    max_retries: Option<u32>,
12    current_attempt: u32,
13}
14
15impl ReconnectPolicy {
16    /// 创建新的重连策略
17    ///
18    /// - `base_delay`: 首次重连等待时间
19    /// - `max_delay`: 最大等待时间上限
20    /// - `max_retries`: 最大重试次数,None 表示无限重试
21    pub fn new(base_delay: Duration, max_delay: Duration, max_retries: Option<u32>) -> Self {
22        Self {
23            base_delay,
24            max_delay,
25            max_retries,
26            current_attempt: 0,
27        }
28    }
29
30    /// 默认策略:1秒起始,30秒上限,无限重试
31    pub fn default_policy() -> Self {
32        Self::new(Duration::from_secs(1), Duration::from_secs(30), None)
33    }
34
35    /// 获取下一次重连的等待时间
36    ///
37    /// 返回 None 表示已达到最大重试次数,应停止重连。
38    pub fn next_delay(&mut self) -> Option<Duration> {
39        if let Some(max) = self.max_retries {
40            if self.current_attempt >= max {
41                return None;
42            }
43        }
44
45        let multiplier = 1u32.checked_shl(self.current_attempt).unwrap_or(u32::MAX);
46        let delay = self.base_delay.saturating_mul(multiplier);
47        let delay = delay.min(self.max_delay);
48
49        self.current_attempt += 1;
50
51        Some(delay)
52    }
53
54    /// 重置重连计数(连接成功后调用)
55    pub fn reset(&mut self) {
56        self.current_attempt = 0;
57    }
58
59    /// 当前已重试次数
60    pub fn attempts(&self) -> u32 {
61        self.current_attempt
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_exponential_backoff() {
71        let mut policy =
72            ReconnectPolicy::new(Duration::from_secs(1), Duration::from_secs(30), None);
73
74        assert_eq!(policy.next_delay(), Some(Duration::from_secs(1)));
75        assert_eq!(policy.next_delay(), Some(Duration::from_secs(2)));
76        assert_eq!(policy.next_delay(), Some(Duration::from_secs(4)));
77        assert_eq!(policy.next_delay(), Some(Duration::from_secs(8)));
78        assert_eq!(policy.next_delay(), Some(Duration::from_secs(16)));
79        // Capped at max_delay
80        assert_eq!(policy.next_delay(), Some(Duration::from_secs(30)));
81        assert_eq!(policy.next_delay(), Some(Duration::from_secs(30)));
82    }
83
84    #[test]
85    fn test_reset() {
86        let mut policy =
87            ReconnectPolicy::new(Duration::from_secs(1), Duration::from_secs(30), None);
88
89        policy.next_delay();
90        policy.next_delay();
91        assert_eq!(policy.attempts(), 2);
92
93        policy.reset();
94        assert_eq!(policy.attempts(), 0);
95        assert_eq!(policy.next_delay(), Some(Duration::from_secs(1)));
96    }
97
98    #[test]
99    fn test_max_retries() {
100        let mut policy =
101            ReconnectPolicy::new(Duration::from_secs(1), Duration::from_secs(30), Some(3));
102
103        assert!(policy.next_delay().is_some());
104        assert!(policy.next_delay().is_some());
105        assert!(policy.next_delay().is_some());
106        assert!(policy.next_delay().is_none()); // 达到最大重试
107    }
108}