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:
@@ -4,7 +4,7 @@ use sqlx::postgres::PgPoolOptions;
|
||||
use sqlx::PgPool;
|
||||
use crate::error::SaasResult;
|
||||
|
||||
const SCHEMA_VERSION: i32 = 4;
|
||||
const SCHEMA_VERSION: i32 = 5;
|
||||
|
||||
const SCHEMA_SQL: &str = r#"
|
||||
CREATE TABLE IF NOT EXISTS saas_schema_version (
|
||||
@@ -337,6 +337,11 @@ CREATE TABLE IF NOT EXISTS refresh_tokens (
|
||||
CREATE INDEX IF NOT EXISTS idx_refresh_account ON refresh_tokens(account_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_refresh_jti ON refresh_tokens(jti);
|
||||
CREATE INDEX IF NOT EXISTS idx_refresh_expires ON refresh_tokens(expires_at);
|
||||
|
||||
-- Performance: expression indexes for date-range queries on TEXT timestamp columns
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_day ON usage_records((SUBSTRING(created_at, 1, 10)));
|
||||
CREATE INDEX IF NOT EXISTS idx_relay_day ON relay_tasks((SUBSTRING(created_at, 1, 10)));
|
||||
CREATE INDEX IF NOT EXISTS idx_relay_time ON relay_tasks(created_at);
|
||||
"#;
|
||||
|
||||
const SEED_ROLES: &str = r#"
|
||||
@@ -351,10 +356,11 @@ ON CONFLICT (id) DO NOTHING;
|
||||
/// 初始化数据库
|
||||
pub async fn init_db(database_url: &str) -> SaasResult<PgPool> {
|
||||
let pool = PgPoolOptions::new()
|
||||
.max_connections(20)
|
||||
.min_connections(2)
|
||||
.acquire_timeout(std::time::Duration::from_secs(5))
|
||||
.idle_timeout(std::time::Duration::from_secs(600))
|
||||
.max_connections(50)
|
||||
.min_connections(5)
|
||||
.acquire_timeout(std::time::Duration::from_secs(10))
|
||||
.idle_timeout(std::time::Duration::from_secs(300))
|
||||
.max_lifetime(std::time::Duration::from_secs(1800))
|
||||
.connect(database_url)
|
||||
.await?;
|
||||
|
||||
@@ -387,7 +393,7 @@ pub async fn init_db(database_url: &str) -> SaasResult<PgPool> {
|
||||
|
||||
/// 如果 accounts 表为空且环境变量已设置,自动创建 super_admin 账号
|
||||
/// 或者更新现有 admin 用户的角色为 super_admin
|
||||
async fn seed_admin_account(pool: &PgPool) -> SaasResult<()> {
|
||||
pub async fn seed_admin_account(pool: &PgPool) -> SaasResult<()> {
|
||||
let admin_username = std::env::var("ZCLAW_ADMIN_USERNAME")
|
||||
.unwrap_or_else(|_| "admin".to_string());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user