refactor(saas): 架构重构 + 性能优化 — 借鉴 loco-rs 模式
Phase 0: 知识库
- docs/knowledge-base/loco-rs-patterns.md — loco-rs 10 个可借鉴模式研究
Phase 1: 数据层重构
- crates/zclaw-saas/src/models/ — 15 个 FromRow 类型化模型
- Login 3 次查询合并为 1 次 AccountLoginRow 查询
- 所有 service 文件从元组解构迁移到 FromRow 结构体
Phase 2: Worker + Scheduler 系统
- crates/zclaw-saas/src/workers/ — Worker trait + 5 个具体实现
- crates/zclaw-saas/src/scheduler.rs — TOML 声明式调度器
- crates/zclaw-saas/src/tasks/ — CLI 任务系统
Phase 3: 性能修复
- Relay N+1 查询 → 精准 SQL (relay/handlers.rs)
- Config RwLock → AtomicU32 无锁 rate limit (state.rs, middleware.rs)
- SSE std::sync::Mutex → tokio::sync::Mutex (relay/service.rs)
- /auth/refresh 阻塞清理 → Scheduler 定期执行
Phase 4: 多环境配置
- config/saas-{development,production,test}.toml
- ZCLAW_ENV 环境选择 + ZCLAW_SAAS_CONFIG 精确覆盖
- scheduler 配置集成到 TOML
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::time::Instant;
|
||||
use tokio::sync::RwLock;
|
||||
use crate::config::SaaSConfig;
|
||||
use crate::workers::WorkerDispatcher;
|
||||
|
||||
/// 全局应用状态,通过 Axum State 共享
|
||||
#[derive(Clone)]
|
||||
@@ -17,19 +19,39 @@ pub struct AppState {
|
||||
pub jwt_secret: secrecy::SecretString,
|
||||
/// 速率限制: account_id → 请求时间戳列表
|
||||
pub rate_limit_entries: Arc<dashmap::DashMap<String, Vec<Instant>>>,
|
||||
/// 角色权限缓存: role_id → permissions list
|
||||
pub role_permissions_cache: Arc<dashmap::DashMap<String, Vec<String>>>,
|
||||
/// 无锁 rate limit RPM(从 config 同步,避免每个请求获取 RwLock)
|
||||
rate_limit_rpm: Arc<AtomicU32>,
|
||||
/// Worker 调度器 (异步后台任务)
|
||||
pub worker_dispatcher: WorkerDispatcher,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(db: PgPool, config: SaaSConfig) -> anyhow::Result<Self> {
|
||||
pub fn new(db: PgPool, config: SaaSConfig, worker_dispatcher: WorkerDispatcher) -> anyhow::Result<Self> {
|
||||
let jwt_secret = config.jwt_secret()?;
|
||||
let rpm = config.rate_limit.requests_per_minute;
|
||||
Ok(Self {
|
||||
db,
|
||||
config: Arc::new(RwLock::new(config)),
|
||||
jwt_secret,
|
||||
rate_limit_entries: Arc::new(dashmap::DashMap::new()),
|
||||
role_permissions_cache: Arc::new(dashmap::DashMap::new()),
|
||||
rate_limit_rpm: Arc::new(AtomicU32::new(rpm)),
|
||||
worker_dispatcher,
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取当前 rate limit RPM(无锁读取)
|
||||
pub fn rate_limit_rpm(&self) -> u32 {
|
||||
self.rate_limit_rpm.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// 更新 rate limit RPM(配置热更新时调用)
|
||||
pub fn set_rate_limit_rpm(&self, rpm: u32) {
|
||||
self.rate_limit_rpm.store(rpm, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// 清理过期的限流条目 (60 秒窗口外的记录)
|
||||
pub fn cleanup_rate_limit_entries(&self) {
|
||||
let window_start = Instant::now() - std::time::Duration::from_secs(60);
|
||||
|
||||
Reference in New Issue
Block a user