fix(saas): P1 审计修复 — 连接池断路器 + Worker重试 + XSS防护 + 状态机SQL解析器
P1 修复内容: - F7: health handler 连接池容量检查 (80%阈值返回503 degraded) - F9: SSE spawned task 并发限制 (Semaphore 16 permits) - F10: Key Pool 单次 JOIN 查询优化 (消除 N+1) - F12: CORS panic → 配置错误 - F14: 连接池使用率计算修正 (ratio = used*100/total) - F15: SQL 迁移解析器替换为状态机 (支持 $$, DO $body$, 存储过程) - Worker 重试机制: 失败任务通过 mpsc channel 重新入队 - DOMPurify XSS 防护 (PipelineResultPreview) - Admin V2: ErrorBoundary + SWR全局配置 + 请求优化
This commit is contained in:
@@ -67,7 +67,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn health_handler(State(state): State<AppState>) -> axum::Json<serde_json::Value> {
|
||||
async fn health_handler(
|
||||
State(state): State<AppState>,
|
||||
) -> (axum::http::StatusCode, axum::Json<serde_json::Value> ) {
|
||||
// health 必须独立快速返回,用 3s 超时避免连接池满时阻塞
|
||||
let db_healthy = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(3),
|
||||
@@ -77,15 +79,41 @@ async fn health_handler(State(state): State<AppState>) -> axum::Json<serde_json:
|
||||
.map(|r| r.is_ok())
|
||||
.unwrap_or(false);
|
||||
|
||||
let status = if db_healthy { "healthy" } else { "degraded" };
|
||||
let _code = if db_healthy { 200 } else { 503 };
|
||||
// 连接池容量检查: 使用率 >= 80% 返回 503 (degraded)
|
||||
let pool = &state.db;
|
||||
let total = pool.options().get_max_connections() as usize;
|
||||
if total > 0 {
|
||||
let idle = pool.num_idle() as usize;
|
||||
let used = total - idle;
|
||||
let ratio = used * 100 / total;
|
||||
if ratio >= 80 {
|
||||
return (
|
||||
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
||||
axum::Json(serde_json::json!({
|
||||
"status": "degraded",
|
||||
"database": true,
|
||||
"database_pool": {
|
||||
"usage_pct": ratio,
|
||||
"used": used,
|
||||
"total": total,
|
||||
},
|
||||
"timestamp": chrono::Utc::now().to_rfc3339(),
|
||||
"version": env!("CARGO_PKG_VERSION"),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
axum::Json(serde_json::json!({
|
||||
let status = if db_healthy { "healthy" } else { "degraded" };
|
||||
let code = if db_healthy {
|
||||
axum::http::StatusCode::OK } else { axum::http::StatusCode::SERVICE_UNAVAILABLE };
|
||||
|
||||
(code, axum::Json(serde_json::json!({
|
||||
"status": status,
|
||||
"database": db_healthy,
|
||||
"timestamp": chrono::Utc::now().to_rfc3339(),
|
||||
"version": env!("CARGO_PKG_VERSION"),
|
||||
}))
|
||||
})))
|
||||
}
|
||||
|
||||
async fn build_router(state: AppState) -> axum::Router {
|
||||
|
||||
Reference in New Issue
Block a user