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:
iven
2026-03-29 19:21:48 +08:00
parent 5fdf96c3f5
commit 8b9d506893
64 changed files with 3348 additions and 520 deletions

View File

@@ -0,0 +1,236 @@
# loco-rs 架构模式研究 — zclaw-saas 重构参考
> 本文档记录 loco-rs (https://loco.rs) 的架构模式分析,评估其在 zclaw-saas 重构中的适用性。
> 创建时间: 2026-03-29
## 1. loco-rs 概述
- **定位**: "Rust on Rails" — 约定优于配置的全栈 Web 框架
- **技术栈**: Axum + SeaORM + PostgreSQL/SQLite
- **成熟度**: ~8K+ GitHub stars, 131+ contributors
- **官方站点**: https://loco.rs
## 2. 10 个可借鉴模式及评估
### 2.1 模式一: Worker trait后台任务抽象⭐ 高价值
**loco-rs 实现**:
- 基于 `sidekiq-rs``Worker` trait支持强类型参数
- 三种模式: `BackgroundQueue`Redis 队列)、`BackgroundAsync`(进程内 tokio`ForegroundBlocking`(同步)
- Worker 在 `Hooks::connect_workers()` 中注册
- 支持重试、延迟执行
**zclaw-saas 现状**:
- `main.rs` 中用 `tokio::spawn` + 手动 `interval` 循环
- 无重试、无命名、无观察性
**建议**: 采用框架无关的 Worker trait不依赖 Redis先用 `tokio::spawn` + channel未来可迁移到 Redis 队列。
```rust
// 建议实现
#[async_trait]
pub trait Worker: Send + Sync + 'static {
type Args: Serialize + DeserializeOwned + Send + Sync;
fn name(&self) -> &str;
async fn perform(&self, db: &PgPool, args: Self::Args) -> Result<(), SaasError>;
fn max_retries(&self) -> u32 { 3 }
}
```
---
### 2.2 模式二: 声明式 Scheduler ⭐ 高价值
**loco-rs 实现**:
- YAML 配置的 cron/interval 定时任务
- 支持 shell 命令或注册的 Task
- 按环境配置、按 tag 分组
**zclaw-saas 现状**:
- 硬编码 `tokio::spawn` + `Duration::from_secs(300)`
- 修改定时策略需要改代码重新编译
**建议**: 用 TOML 配置 scheduler与项目已有 TOML 基础一致),支持 interval 表达式。
```toml
[scheduler]
jobs = [
{ name = "cleanup_rate_limit", interval = "5m", task = "cleanup_rate_limit" },
{ name = "cleanup_devices", interval = "24h", task = "cleanup_devices" },
]
```
---
### 2.3 模式三: 类型化数据库模型 (FromRow) ⭐⭐ 最高价值
**loco-rs 实现**:
- SeaORM 实体自动生成(`sea-orm-cli generate entity`
- 强类型字段、关系、验证
**zclaw-saas 现状**:
- 原始元组解构 `(String, String, String, ...)`
- 无编译期字段检查,容易出错
**建议**: 不使用 SeaORM但用 `#[derive(sqlx::FromRow)]` 实现同样效果。
```rust
// Before (当前)
let (id, username, email, role, status) = sqlx::query_as::<_, (String, String, String, String, String)>(...)
// 5 个 String 参数,顺序错误编译器无法发现
// After (目标)
#[derive(sqlx::FromRow)]
pub struct AccountRow {
pub id: String,
pub username: String,
pub email: String,
pub role: String,
pub status: String,
pub created_at: DateTime<Utc>,
}
let row = sqlx::query_as::<_, AccountRow>("SELECT ...").fetch_one(db).await?;
```
---
### 2.4 模式四: SQL 迁移系统 ⭐ 高价值
**loco-rs 实现**:
- 迁移优先,先写 migration再从 DB 自动生成实体
- `sea-orm-cli migrate` 管理版本
**zclaw-saas 现状**:
- `db.rs` 内联 `SCHEMA_SQL` 常量,每次启动执行
- 无回滚能力DDL 混在应用代码中
- `SCHEMA_VERSION = 5` 手动追踪
**建议**: 使用 `sqlx-cli` 的迁移系统。
```
migrations/
├── 20260329000001_initial_schema.sql
├── 20260329000002_fix_timestamps.sql
└── 20260329000003_add_indexes.sql
```
---
### 2.5 模式五: CLI Task 系统 ⭐ 中等价值
**loco-rs 实现**:
- `Task` trait 用于手动执行运维操作
- `cargo loco task <NAME>` 命令行调用
- 支持参数传递
**zclaw-saas 现状**:
- 运维任务seed admin、schema 初始化)嵌入在 `db.rs``init_db()`
- 无法手动触发、无法传参
**建议**: 添加 Task trait + CLI 解析。
```rust
#[async_trait]
pub trait Task: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
async fn run(&self, state: &AppState, args: &HashMap<String, String>) -> SaasResult<()>;
}
```
---
### 2.6 模式六: 多环境配置 ⭐ 中等价值
**loco-rs 实现**:
- `development.yaml` / `production.yaml` / `test.yaml`
- 通过 `LOCO_ENV` 环境变量选择
- 支持 Tera 模板语法引用环境变量
**zclaw-saas 现状**:
- 单个 `saas-config.toml` 文件
- 通过 `ZCLAW_SAAS_CONFIG` 路径覆盖
**建议**: 采用环境分离配置。
```
config/
├── saas-development.toml
├── saas-production.toml
└── saas-test.toml
```
---
### 2.7 模式七: 可配置中间件栈 ⭐ 低价值
**loco-rs 实现**:
- YAML 配置 CORS、timeout、payload limit 等中间件参数
- Per-handler 和 per-route-group 的中间件层
**zclaw-saas 现状**:
- CORS origins、timeout 等硬编码在 `main.rs``build_router()`
**建议**: 当前优先级低,后续可将中间件参数移入 TOML 配置。
---
### 2.8 模式八: 集成测试辅助 ⭐ 中等价值
**loco-rs 实现**:
- `request::(|request, ctx| async { ... })` 风格的请求测试
- 自动启动测试 app + 测试数据库
- `assert_debug_snapshot!` 快照测试
**zclaw-saas 现状**:
- 基础的 `tests/account_test.rs`
**建议**: 添加测试辅助工具app 启动 + 请求发送 + fixture
---
### 2.9 ~~模式九: Fat Model~~ — 不建议采用
**loco-rs 实现**: 业务逻辑放在 `impl ActiveModel`Active Record 模式)
**原因**: 依赖 SeaORM 实体结构。zclaw-saas 使用 SQLxService Layer 模式更适合。
### 2.10 ~~模式十: SeaORM / YAML 配置~~ — 不建议采用
**原因**:
- SeaORM 引入 ORM 抽象层,与现有 SQLx 原始查询冲突
- YAML 在 Rust 生态中不如 TOML 类型安全
- loco-rs creator jondot 确认无增量集成路径,必须创建新项目迁移
## 3. zclaw-saas 与 loco-rs 架构对照
| 维度 | loco-rs | zclaw-saas (当前) | 建议 |
|------|---------|-------------------|------|
| Web 框架 | Axum | Axum | 保持不变 |
| 数据库层 | SeaORM (ORM) | SQLx (原始查询) | 保持 SQLx + FromRow |
| 后台任务 | sidekiq-rs (Redis) | tokio::spawn (手动) | **引入 Worker trait** |
| 定时任务 | YAML Scheduler | 硬编码 interval | **引入 TOML Scheduler** |
| 数据库模型 | 自动生成实体 | 元组解构 | **引入 FromRow** |
| 迁移系统 | sea-orm-cli | 内联 SQL | **引入 sqlx-cli** |
| 错误处理 | 统一 Error enum | SaasError (thiserror) | 已优秀,保持不变 |
| 配置系统 | YAML per-env | TOML 单文件 | **引入多环境配置** |
| CLI 任务 | Task trait | 嵌入 init 代码 | **引入 Task trait** |
| 测试 | 请求测试辅助 | 基础测试 | **引入测试辅助** |
## 4. 实施优先级
| 优先级 | 模式 | 价值 | 工作量 |
|--------|------|------|--------|
| 1 | FromRow 类型化模型 + 迁移系统 | 最高 | 中 |
| 2 | Worker trait 后台任务 | 高 | 低 |
| 3 | 声明式 Scheduler | 高 | 低 |
| 4 | CLI Task 系统 | 中 | 低 |
| 5 | 多环境配置 | 中 | 低 |
| 6 | 集成测试辅助 | 中 | 中 |
| 7 | 可配置中间件 | 低 | 低 |
## 5. 参考
- [loco.rs 官方文档](https://loco.rs/docs/the-app/)
- [loco-rs GitHub](https://github.com/loco-rs/loco)
- [Reddit: 如何从 Axum 迁移到 loco-rs](https://www.reddit.com/r/rust/comments/1g9hc1z/how_to_integratemigrate_to_locors_from_axum_app/)
- [Shuttle.dev: 介绍 Loco](https://www.shuttle.dev/blog/2023/12/20/loco-rust-rails)