mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-07 00:05:49 +00:00
5.8 KiB
5.8 KiB
后台调度器实现完成
概述
本次实现添加了两个关键的后台调度器,用于自动化账户令牌刷新和会话清理。这些调度器是 TypeScript 原版 codex-proxy 项目中核心功能的 Rust 原生重写。
已实现的功能
1. RefreshScheduler - OAuth 刷新调度器
位置: src/scheduler/refresh.rs
功能:
- ✅ 在 JWT 令牌
exp - margin时刻自动调度刷新 - ✅ 指数退避重试策略(5次尝试:5s → 15s → 45s → 135s → 300s)
- ✅ 永久失败检测(识别
invalid_grant、invalid_token、账户封禁等错误) - ✅ 临时失败的恢复调度(10分钟后重试)
- ✅ 崩溃恢复机制:
refreshing状态 → 立即重试expired+ 有 refreshToken → 延迟重试(30秒起,每个账户间隔2秒)
- ✅ 并发控制(防止同一账户重复刷新)
- ✅ JWT 解析和过期时间计算
- ✅ 优雅关闭支持
关键实现细节:
// 永久错误检测
const BAN_ERRORS: &[&str] = &["account has been deactivated", "refresh_token_reused"];
const EXPIRED_ERRORS: &[&str] = &[
"invalid_grant",
"invalid_token",
"access_denied",
"refresh_token_expired",
];
// 指数退避算法
let backoff = BASE_DELAY_MS.saturating_mul(3_u64.pow(attempt - 1));
let backoff = backoff.min(300_000); // 最大5分钟
使用方式:
let scheduler = RefreshScheduler::new(account_service, config);
let handle = scheduler.start().await;
// 优雅关闭
handle.shutdown().await;
2. SessionCleanupScheduler - 会话清理调度器
位置: src/scheduler/session_cleanup.rs
功能:
- ✅ 定期删除过期的管理员会话
- ✅ 可配置的清理间隔
- ✅ 优雅关闭支持
- ✅ 直接操作 SQLite 数据库(高效、轻量级)
实现:
async fn cleanup_expired_sessions(&self) -> Result<u64, sqlx::Error> {
let now = chrono::Utc::now().to_rfc3339();
let result = sqlx::query("DELETE FROM admin_sessions WHERE expires_at < ?")
.bind(&now)
.execute(&self.db)
.await?;
Ok(result.rows_affected())
}
3. 调度器基础设施
位置: src/scheduler/types.rs, src/scheduler/mod.rs
提供:
- ✅
SchedulerHandle- 统一的调度器句柄,支持优雅关闭 - ✅
SchedulerError- 类型化的错误处理 - ✅
SchedulerResult<T>- 统一的结果类型
与原 TypeScript 版本的对比
TypeScript 版本(参考)
- 使用
setTimeout和setInterval - 回调风格的异步处理
- 内存锁文件用于跨进程同步
Rust 版本(新实现)
- 使用
tokio::spawn和tokio::time async/await风格RwLock用于线程安全的状态管理- 类型安全的错误处理
架构设计决策
1. 避免异步递归
问题:schedule_one 调用 do_refresh,do_refresh 又可能调用 schedule_one,导致无限递归。
解决方案:
schedule_one()- 初始调度,直接在定时器中执行刷新schedule_next_refresh()- 刷新成功后调度下次刷新,避免递归
2. 并发控制
使用 in_flight: Arc<RwLock<HashMap<String, Instant>>> 跟踪正在刷新的账户,防止重复刷新。
3. 优雅关闭
所有调度器返回 SchedulerHandle,通过 mpsc::channel 实现优雅关闭:
tokio::select! {
_ = ticker.tick() => { /* 执行任务 */ }
_ = shutdown_rx.recv() => { /* 退出循环 */ }
}
集成到 AccountService
新增方法:
impl AccountService {
/// 列出所有账户用于刷新调度器
pub async fn list_all_for_refresh(&self) -> Result<Vec<StoredAccount>, AccountServiceError> {
self.repository()?
.list_all()
.await
.map_err(|_| AccountServiceError::List)
}
}
// 为 RefreshAccountError 实现 Display trait
impl std::fmt::Display for RefreshAccountError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// ... 格式化输出
}
}
测试状态
✅ 编译通过: cargo check --lib
✅ Clippy 通过: cargo clippy --all-targets --all-features --locked -- -D warnings
✅ 格式化: cargo fmt
✅ 现有测试通过: 所有 152 个集成测试保持通过
下一步
根据计划文档 (line 3002, 3005),仍需实现:
-
启动集成:
- 在
main.rs启动时初始化调度器 - 在优雅关闭时停止调度器
- 在
-
高级功能(可选):
- 跨进程刷新锁(用于多实例部署)
- 磁盘刷新令牌同步(防止一次性 RT 被多次消费)
- 配额刷新调度器
- 模型刷新调度器
- 指纹更新调度器
-
监控和可观测性:
- 调度器健康检查端点
- 刷新成功/失败指标
- 活跃定时器数量监控
提交信息
feat: add background refresh and session cleanup schedulers
- 实现 RefreshScheduler 用于在 JWT 过期前自动刷新访问令牌
- 在 exp - margin 时刻调度刷新
- 指数退避重试(5次尝试:5s → 15s → 45s → 135s → 300s)
- 永久失败检测(invalid_grant / invalid_token)
- 临时失败的恢复调度(10分钟)
- 崩溃恢复:refreshing → 立即重试,expired + refreshToken → 延迟重试
- 实现 SessionCleanupScheduler 用于定期清理过期的管理员会话
- 所有调度器支持优雅关闭
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
文件清单
新增文件:
src/scheduler/mod.rs- 模块导出src/scheduler/types.rs- 调度器类型和错误定义src/scheduler/refresh.rs- OAuth 刷新调度器(385 行)src/scheduler/session_cleanup.rs- 会话清理调度器(66 行)
修改文件:
src/lib.rs- 添加pub mod scheduler;src/codex/accounts/service/mod.rs- 添加list_all_for_refresh()和Displayimpl
总计:554 行新代码