feat(gateway): 补齐号池主动探测后台任务 (#342)

- 解析 pool_advanced 主动探测开关与间隔配置
- 对齐 Python 版本的探测间隔默认值和范围限制
- 新增号池配额主动探测 worker
- 支持 codex、kiro、antigravity provider
- 使用 Redis 时间戳和 provider 级锁避免重复探测
- 接入 gateway 后台任务并补充测试
This commit is contained in:
AAEE86
2026-04-26 23:48:31 +08:00
committed by GitHub
parent baa0ddd787
commit f3a9fd4c82
10 changed files with 736 additions and 26 deletions

View File

@@ -21,7 +21,12 @@ pub(crate) use self::observability::{
round_to, AdminStatsTimeRange, AdminStatsUsageFilter,
};
pub(crate) use self::provider::oauth::errors::build_internal_control_error_response;
pub(crate) use self::provider::oauth::quota::antigravity::refresh_antigravity_provider_quota_locally;
pub(crate) use self::provider::oauth::quota::codex::refresh_codex_provider_quota_locally;
pub(crate) use self::provider::oauth::quota::kiro::refresh_kiro_provider_quota_locally;
pub(crate) use self::provider::oauth::runtime::provider_oauth_runtime_endpoint_for_provider;
pub(crate) use self::provider::ops::providers::actions::admin_provider_ops_local_action_response;
pub(crate) use self::provider::pool::config::admin_provider_pool_config;
pub(crate) use self::provider::pool_admin::maybe_build_local_admin_pool_response;
pub(crate) use self::provider::{
maybe_build_local_admin_provider_oauth_response, maybe_build_local_admin_providers_response,

View File

@@ -246,6 +246,8 @@ pub(crate) fn admin_provider_pool_config_from_config_value(
rate_limit_cooldown_seconds: 300,
overload_cooldown_seconds: 30,
health_policy_enabled: true,
probing_enabled: false,
probing_interval_minutes: 10,
stream_timeout_threshold: 3,
stream_timeout_window_seconds: 1800,
stream_timeout_cooldown_seconds: 300,
@@ -299,6 +301,16 @@ pub(crate) fn admin_provider_pool_config_from_config_value(
.get("health_policy_enabled")
.and_then(Value::as_bool)
.unwrap_or(true),
probing_enabled: pool_advanced
.get("probing_enabled")
.and_then(Value::as_bool)
.unwrap_or(false),
probing_interval_minutes: pool_advanced
.get("probing_interval_minutes")
.and_then(json_u64)
.filter(|value| *value > 0)
.map(|value| value.min(1440))
.unwrap_or(10),
stream_timeout_threshold: pool_advanced
.get("stream_timeout_threshold")
.and_then(json_u64)
@@ -366,6 +378,8 @@ mod tests {
"rate_limit_cooldown_seconds": 420,
"overload_cooldown_seconds": 45,
"health_policy_enabled": false,
"probing_enabled": true,
"probing_interval_minutes": 20,
"stream_timeout_threshold": 4,
"stream_timeout_window_seconds": 900,
"stream_timeout_cooldown_seconds": 180
@@ -383,11 +397,34 @@ mod tests {
assert_eq!(config.rate_limit_cooldown_seconds, 420);
assert_eq!(config.overload_cooldown_seconds, 45);
assert!(!config.health_policy_enabled);
assert!(config.probing_enabled);
assert_eq!(config.probing_interval_minutes, 20);
assert_eq!(config.stream_timeout_threshold, 4);
assert_eq!(config.stream_timeout_window_seconds, 900);
assert_eq!(config.stream_timeout_cooldown_seconds, 180);
}
#[test]
fn clamps_pool_quota_probe_interval_to_python_range() {
let provider = sample_provider(json!({
"pool_advanced": {
"probing_enabled": true,
"probing_interval_minutes": 2000,
}
}));
let config = admin_provider_pool_config(&provider).expect("pool config should exist");
assert_eq!(config.probing_interval_minutes, 1440);
let provider = sample_provider(json!({
"pool_advanced": {
"probing_enabled": true,
"probing_interval_minutes": 0,
}
}));
let config = admin_provider_pool_config(&provider).expect("pool config should exist");
assert_eq!(config.probing_interval_minutes, 10);
}
#[test]
fn parses_zero_sticky_session_ttl_to_disable_sticky_sessions() {
let config = admin_provider_pool_config_from_config_value(Some(&json!({

View File

@@ -612,6 +612,8 @@ mod tests {
rate_limit_cooldown_seconds: 300,
overload_cooldown_seconds: 30,
health_policy_enabled: true,
probing_enabled: false,
probing_interval_minutes: 10,
stream_timeout_threshold: 3,
stream_timeout_window_seconds: 1800,
stream_timeout_cooldown_seconds: 300,

View File

@@ -37,6 +37,8 @@ pub(crate) struct AdminProviderPoolConfig {
pub(crate) rate_limit_cooldown_seconds: u64,
pub(crate) overload_cooldown_seconds: u64,
pub(crate) health_policy_enabled: bool,
pub(crate) probing_enabled: bool,
pub(crate) probing_interval_minutes: u64,
pub(crate) stream_timeout_threshold: u64,
pub(crate) stream_timeout_window_seconds: u64,
pub(crate) stream_timeout_cooldown_seconds: u64,