1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::error::{parse_retry_after_seconds, HeaderMap};
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
/// EN: Runtime-neutral sleep boundary used by retry execution.
/// 中文:重试执行使用的运行时无关休眠边界。
pub trait RetrySleeper: Send + Sync + fmt::Debug {
/// EN: Sleeps for the provided duration before the next retry attempt.
/// 中文:在下一次重试前按给定时长休眠。
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
}
/// EN: No-op retry sleeper for runtime-neutral custom integrations.
/// 中文:用于运行时无关自定义集成的空操作重试休眠器。
#[derive(Clone, Debug, Default)]
pub struct NoopRetrySleeper;
impl RetrySleeper for NoopRetrySleeper {
fn sleep(&self, _duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
Box::pin(async {})
}
}
/// EN: Decision produced by retry policy classification.
/// 中文:重试策略分类产生的决策。
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum RetryDecision {
/// EN: The operation should not be retried.
/// 中文:不应重试该操作。
DoNotRetry,
/// EN: The operation may be retried, optionally after a server-provided delay.
/// 中文:可以重试该操作,并可选择遵循服务端提供的延迟。
RetryAfter(Option<Duration>),
}
/// EN: Conservative retry policy for transient OpenAI failures.
/// 中文:针对 OpenAI 瞬时故障的保守重试策略。
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct RetryPolicy {
/// EN: Maximum number of retry attempts after the first request.
/// 中文:首次请求之后允许的最大重试次数。
pub max_retries: usize,
/// EN: Initial exponential backoff delay.
/// 中文:指数退避的初始延迟。
pub initial_backoff: Duration,
/// EN: Maximum exponential backoff delay.
/// 中文:指数退避的最大延迟。
pub max_backoff: Duration,
}
impl Default for RetryPolicy {
fn default() -> Self {
Self {
max_retries: 2,
initial_backoff: Duration::from_millis(500),
max_backoff: Duration::from_secs(8),
}
}
}
impl RetryPolicy {
/// EN: Classifies an HTTP status according to documented transient retry candidates.
/// 中文:根据已记录的瞬时重试候选状态码对 HTTP 状态分类。
pub fn classify_status(&self, status: u16, headers: &HeaderMap) -> RetryDecision {
match status {
408 | 409 | 429 | 500..=599 => {
let retry_after = headers
.get("retry-after")
.and_then(parse_retry_after_seconds);
RetryDecision::RetryAfter(retry_after)
}
_ => RetryDecision::DoNotRetry,
}
}
/// EN: Computes capped exponential backoff for a zero-based retry attempt.
/// 中文:为从零开始的重试次数计算有上限的指数退避。
pub fn backoff_delay(&self, retry_attempt: usize) -> Duration {
let factor = 1_u32
.checked_shl(retry_attempt.min(31) as u32)
.unwrap_or(u32::MAX);
self.initial_backoff
.saturating_mul(factor)
.min(self.max_backoff)
}
}