You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

5.3 KiB

定时任务功能设计

概述

为 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

type TaskHandler = (payload?: Record<string, unknown>) => Promise<{ success: boolean; message: string }>;

registerTask(name: string, handler: TaskHandler): void
executeTask(name: string, payload?: Record<string, unknown>): 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、非法表达式校验拒绝。