subx_cli/services/ai/
retry.rs

1use crate::Result;
2use tokio::time::{Duration, sleep};
3
4/// 重試設定
5pub struct RetryConfig {
6    pub max_attempts: usize,
7    pub base_delay: Duration,
8    pub max_delay: Duration,
9    pub backoff_multiplier: f64,
10}
11
12impl Default for RetryConfig {
13    fn default() -> Self {
14        Self {
15            max_attempts: 3,
16            base_delay: Duration::from_millis(1000),
17            max_delay: Duration::from_secs(30),
18            backoff_multiplier: 2.0,
19        }
20    }
21}
22
23/// 使用指數退避機制重試操作
24pub async fn retry_with_backoff<F, Fut, T>(operation: F, config: &RetryConfig) -> Result<T>
25where
26    F: Fn() -> Fut,
27    Fut: std::future::Future<Output = Result<T>>,
28{
29    let mut last_error = None;
30
31    for attempt in 0..config.max_attempts {
32        match operation().await {
33            Ok(result) => return Ok(result),
34            Err(e) => {
35                last_error = Some(e);
36
37                if attempt < config.max_attempts - 1 {
38                    let delay = std::cmp::min(
39                        Duration::from_millis(
40                            (config.base_delay.as_millis() as f64
41                                * config.backoff_multiplier.powi(attempt as i32))
42                                as u64,
43                        ),
44                        config.max_delay,
45                    );
46                    sleep(delay).await;
47                }
48            }
49        }
50    }
51
52    Err(last_error.unwrap())
53}