From e42b0a6a376b8ceeb5412c3d202c3a97312727bb Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Thu, 14 May 2026 11:49:23 +0800 Subject: [PATCH] add scheduled tasks feature design spec Co-Authored-By: Claude Opus 4.7 --- .../specs/2026-05-14-scheduled-tasks-design.md | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-14-scheduled-tasks-design.md diff --git a/docs/superpowers/specs/2026-05-14-scheduled-tasks-design.md b/docs/superpowers/specs/2026-05-14-scheduled-tasks-design.md new file mode 100644 index 0000000..d4d3baf --- /dev/null +++ b/docs/superpowers/specs/2026-05-14-scheduled-tasks-design.md @@ -0,0 +1,141 @@ +# 定时任务功能设计 + +## 概述 + +为 Nuxt 应用增加定时任务(cron job)功能,支持系统预定义任务和用户可配置任务,通过 REST API 和 Nuxt UI 管理界面控制,处理服务重启恢复。 + +## 技术选型 + +- **cron 解析**:`croner` — 纯 JS,TypeScript 友好,零原生依赖,bun 兼容 +- **持久化**:Drizzle ORM + SQLite(复用现有技术栈) +- **调度引擎**:Nitro 插件 + 内存调度器 + +## 核心架构 + +``` +Nitro Plugin (server/plugins/03.scheduler.ts) +├── Scheduler Engine — 主调度器,管理所有活跃任务 +│ ├── croner — cron 表达式解析与触发 +│ └── Executor Pool — 并发控制(max N,可配置) +├── Task Store — Drizzle DB 持久化 +├── Task Registry — 系统任务名称→处理函数的映射 +├── REST API — CRUD + 手动触发 + 执行日志查询 +└── Admin UI — Nuxt UI 管理页面 +``` + +## 数据模型 + +### scheduled_tasks + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | text (PK) | uuid | +| name | text | 任务名称 | +| cron_expression | text | 标准 5 段 cron 表达式 | +| type | text | `"function"` 或 `"http"` | +| function_name | text (nullable) | 系统注册的函数名 | +| function_payload | text (nullable) | JSON string,传给函数的参数 | +| http_method | text (nullable) | GET / POST / PUT / DELETE | +| http_url | text (nullable) | 请求 URL | +| http_headers | text (nullable) | JSON string,自定义请求头 | +| http_body | text (nullable) | 请求体 | +| catch_up | integer | 0=跳过, 1=补执行 | +| enabled | integer | 0=暂停, 1=启用 | +| max_retries | integer | 失败重试次数,默认 0 | +| retry_delay_seconds | integer | 重试间隔秒,默认 60 | +| timeout_seconds | integer | 超时秒,默认 300 | +| created_at | text | | +| updated_at | text | | + +### task_execution_logs + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | text (PK) | uuid | +| task_id | text (FK) | 关联 scheduled_tasks.id | +| status | text | `"running"` / `"success"` / `"failed"` | +| started_at | text | | +| finished_at | text (nullable) | | +| error_message | text (nullable) | | +| result_summary | text (nullable) | 简要结果描述 | + +## API 设计 + +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | /api/scheduler/tasks | 列出任务(分页+筛选) | +| GET | /api/scheduler/tasks/:id | 任务详情+最近执行日志 | +| POST | /api/scheduler/tasks | 创建任务 | +| PUT | /api/scheduler/tasks/:id | 更新任务 | +| DELETE | /api/scheduler/tasks/:id | 删除任务(保留日志) | +| POST | /api/scheduler/tasks/:id/trigger | 手动触发一次 | +| POST | /api/scheduler/tasks/:id/toggle | 启用/暂停 | +| GET | /api/scheduler/executions | 执行日志列表 | +| GET | /api/scheduler/stats | 汇总统计 | + +创建/更新任务时 Scheduler Engine 实时热更新,无需重启服务。 + +## Scheduler 生命周期 + +### 启动 +1. 从 DB 加载所有 `enabled=1` 的任务 +2. 对每个任务解析 cron,计算最近应触发时间 +3. `catchUp=1` 且已错过触发时间 → 补执行一次 +4. 注册到 croner,进入调度循环 + +### 热更新 +1. API 写入 DB 后通知 Scheduler Engine +2. 增量同步:新增→注册 / 更新→替换 / 删除→取消 +3. 同步失败仅记日志,DB 已写入,重启后自行纠正 + +### 重启恢复 +1. `status=running` 的执行日志全部标记 `failed` +2. 按 catchUp 字段处理每个启用任务 + +### 并发控制 +- Executor Pool 维护信号量 +- 槽位满时排队,超时强制标记失败 + +## Task Registry + +```typescript +type TaskHandler = (payload?: Record) => Promise<{ success: boolean; message: string }>; + +registerTask(name: string, handler: TaskHandler): void +executeTask(name: string, payload?: Record): Promise<{ success: boolean; message: string }> +listRegisteredTasks(): string[] +``` + +系统任务在代码中注册,通过 API 创建调度时引用 `functionName`。HTTP 类型不走 Registry,直接用 `fetch()`。 + +## 前端管理页面 + +- `/admin/scheduler` — 任务列表 + 统计栏 + 创建/编辑弹窗 +- `/admin/scheduler/:id` — 任务详情 + 执行历史时间线 + +创建/编辑弹窗:名称、类型切换、cron 输入+人类可读预览+快捷预设、函数选择下拉、HTTP 配置、高级设置(catchUp/超时/重试)、测试运行按钮。 + +## 错误处理 + +| 场景 | 处理 | +|------|------| +| cron 表达式非法 | 校验拒绝(422),已存在的标记 disabled + ERROR 日志 | +| DB 读取失败 | 服务启动失败(fast fail) | +| Registry 未找到函数 | 执行时跳过 + ERROR 日志 | +| 执行超时 | 强制终止,标记 failed | +| 执行异常 | 按 retryCount 重试,全部失败记日志 | +| HTTP 请求失败 | 同上,记录状态码和响应摘要 | +| 并发池满 | 排队等待,WARN 日志 | +| croner 内部异常 | 全局 catch,不影响其他任务 | + +执行日志保留 30 天,定期清理防 SQLite 膨胀。 + +## 测试策略 + +| 层 | 覆盖 | 工具 | +|----|------|------| +| 单元 | cron 解析、Registry、Executor Pool、数据校验 | vitest | +| 集成 | API CRUD 流程、热更新、手动触发 | vitest + 内存 SQLite | +| E2E | 前端管理页面操作流程 | 手动验证 | + +核心场景:创建→调度→触发→日志、热更新替换 cron、并发池满排队、重启恢复 catchUp、非法表达式校验拒绝。