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:
iven
2026-03-30 14:21:39 +08:00
parent bc8c77e7fe
commit ba2c6a6105
38 changed files with 490 additions and 236 deletions

View File

@@ -42,7 +42,7 @@ export default function Accounts() {
const { data, isLoading } = useQuery({
queryKey: ['accounts'],
queryFn: () => accountService.list(),
queryFn: ({ signal }) => accountService.list(signal),
})
const updateMutation = useMutation({

View File

@@ -26,7 +26,7 @@ export default function AgentTemplates() {
const { data, isLoading } = useQuery({
queryKey: ['agent-templates'],
queryFn: () => agentTemplateService.list(),
queryFn: ({ signal }) => agentTemplateService.list(signal),
})
const createMutation = useMutation({

View File

@@ -21,7 +21,7 @@ export default function ApiKeys() {
const { data, isLoading } = useQuery({
queryKey: ['api-keys'],
queryFn: () => apiKeyService.list(),
queryFn: ({ signal }) => apiKeyService.list(signal),
})
const createMutation = useMutation({

View File

@@ -20,7 +20,7 @@ export default function Config() {
const { data, isLoading } = useQuery({
queryKey: ['config', category],
queryFn: () => configService.list({ category }),
queryFn: ({ signal }) => configService.list({ category }, signal),
})
const updateMutation = useMutation({

View File

@@ -42,12 +42,12 @@ const actionColors: Record<string, string> = {
export default function Dashboard() {
const { data: stats, isLoading: statsLoading, error: statsError } = useQuery({
queryKey: ['dashboard-stats'],
queryFn: () => statsService.dashboard(),
queryFn: ({ signal }) => statsService.dashboard(signal),
})
const { data: logsData, isLoading: logsLoading } = useQuery({
queryKey: ['recent-logs'],
queryFn: () => logService.list({ page: 1, page_size: 10 }),
queryFn: ({ signal }) => logService.list({ page: 1, page_size: 10 }, signal),
})
if (statsError) {

View File

@@ -42,7 +42,7 @@ export default function Logs() {
const { data, isLoading } = useQuery({
queryKey: ['logs', page, actionFilter],
queryFn: () => logService.list({ page, page_size: 20, action: actionFilter }),
queryFn: ({ signal }) => logService.list({ page, page_size: 20, action: actionFilter }, signal),
})
const columns: ProColumns<OperationLog>[] = [

View File

@@ -20,12 +20,12 @@ export default function Models() {
const { data, isLoading } = useQuery({
queryKey: ['models'],
queryFn: () => modelService.list(),
queryFn: ({ signal }) => modelService.list(signal),
})
const { data: providersData } = useQuery({
queryKey: ['providers-for-select'],
queryFn: () => providerService.list(),
queryFn: ({ signal }) => providerService.list(signal),
})
const createMutation = useMutation({

View File

@@ -26,18 +26,18 @@ export default function Prompts() {
const { data, isLoading } = useQuery({
queryKey: ['prompts'],
queryFn: () => promptService.list(),
queryFn: ({ signal }) => promptService.list(signal),
})
const { data: detailData } = useQuery({
queryKey: ['prompt-detail', detailName],
queryFn: () => promptService.get(detailName!),
queryFn: ({ signal }) => promptService.get(detailName!, signal),
enabled: !!detailName,
})
const { data: versionsData } = useQuery({
queryKey: ['prompt-versions', detailName],
queryFn: () => promptService.listVersions(detailName!),
queryFn: ({ signal }) => promptService.listVersions(detailName!, signal),
enabled: !!detailName,
})

View File

@@ -22,12 +22,12 @@ export default function Providers() {
const { data, isLoading } = useQuery({
queryKey: ['providers'],
queryFn: () => providerService.list(),
queryFn: ({ signal }) => providerService.list(signal),
})
const { data: keysData, isLoading: keysLoading } = useQuery({
queryKey: ['provider-keys', keyModalProviderId],
queryFn: () => providerService.listKeys(keyModalProviderId!),
queryFn: ({ signal }) => providerService.listKeys(keyModalProviderId!, signal),
enabled: !!keyModalProviderId,
})

View File

@@ -34,7 +34,7 @@ export default function Relay() {
const { data, isLoading } = useQuery({
queryKey: ['relay-tasks', page, statusFilter],
queryFn: () => relayService.list({ page, page_size: 20, status: statusFilter }),
queryFn: ({ signal }) => relayService.list({ page, page_size: 20, status: statusFilter }, signal),
})
const columns: ProColumns<RelayTask>[] = [

View File

@@ -19,12 +19,12 @@ export default function Usage() {
const { data: dailyData, isLoading: dailyLoading, error: dailyError } = useQuery({
queryKey: ['usage-daily', days],
queryFn: () => telemetryService.dailyStats({ days }),
queryFn: ({ signal }) => telemetryService.dailyStats({ days }, signal),
})
const { data: modelData, isLoading: modelLoading } = useQuery({
queryKey: ['usage-model', days],
queryFn: () => telemetryService.modelStats({}),
queryFn: ({ signal }) => telemetryService.modelStats({}, signal),
})
if (dailyError) {