# 任务调度器

<cite>
**本文引用的文件**
- [src/lib/cron/engine.ts](file://src/lib/cron/engine.ts)
- [src/lib/cron/cron-parser.ts](file://src/lib/cron/cron-parser.ts)
- [src/lib/cron/executor.ts](file://src/lib/cron/executor.ts)
- [src/lib/db.ts](file://src/lib/db.ts)
- [src/lib/types.ts](file://src/lib/types.ts)
- [src/app/api/cron-tasks/route.ts](file://src/app/api/cron-tasks/route.ts)
- [src/app/api/cron-tasks/[id]/route.ts](file://src/app/api/cron-tasks/[id]/route.ts)
- [src/app/api/cron-tasks/[id]/execute/route.ts](file://src/app/api/cron-tasks/[id]/execute/route.ts)
- [src/app/api/cron-engine/route.ts](file://src/app/api/cron-engine/route.ts)
- [src/app/api/task-executions/route.ts](file://src/app/api/task-executions/route.ts)
- [src/hooks/use-cron-tasks.ts](file://src/hooks/use-cron-tasks.ts)
- [src/hooks/use-task-executions.ts](file://src/hooks/use-task-executions.ts)
- [src/components/views/schedule-view.tsx](file://src/components/views/schedule-view.tsx)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件系统性地阐述任务调度器的设计与实现，覆盖以下主题：
- 定时检查机制：每分钟扫描一次启用的任务，基于 cron 表达式进行匹配
- 任务匹配算法：支持通配符、步长、范围与枚举组合的字段级匹配
- 执行决策过程：去重并发、会话持久化、结果记录与自动禁用一次性任务
- cron 表达式解析与时间匹配逻辑：字段粒度匹配与人类可读标签转换
- 生命周期管理：自动启动、手动启停、心跳任务与一次性任务处理
- 性能优化策略：并发控制、索引利用、WAL 模式与数据库连接复用
- 配置参数、调试方法与故障排除

## 项目结构
调度器由前端视图、React Hook、API 路由、后端引擎与数据库层协同组成，采用“单例引擎 + 前端可视化”的分层设计。

```mermaid
graph TB
subgraph "前端"
Sched["ScheduleView 组件<br/>schedule-view.tsx"]
HookTasks["useCronTasks Hook<br/>use-cron-tasks.ts"]
HookExec["useTaskExecutions Hook<br/>use-task-executions.ts"]
end
subgraph "API 层"
APITasks["/api/cron-tasks<br/>route.ts"]
APIById["/api/cron-tasks/[id]<br/>route.ts"]
APIExecute["/api/cron-tasks/[id]/execute<br/>route.ts"]
APIEngine["/api/cron-engine<br/>route.ts"]
APIExecList["/api/task-executions<br/>route.ts"]
end
subgraph "后端引擎"
Engine["CronEngine 单例<br/>engine.ts"]
Parser["Cron 匹配器<br/>cron-parser.ts"]
Executor["任务执行器<br/>executor.ts"]
end
subgraph "数据层"
DB["SQLite 数据库<br/>db.ts"]
Types["类型定义<br/>types.ts"]
end
Sched --> HookTasks
Sched --> HookExec
HookTasks --> APITasks
HookTasks --> APIById
HookTasks --> APIExecute
HookExec --> APIExecList
APITasks --> Engine
APIById --> Engine
APIExecute --> Executor
APIEngine --> Engine
Engine --> Parser
Engine --> Executor
Engine --> DB
Executor --> DB
APITasks --> DB
APIById --> DB
APIExecute --> DB
APIExecList --> DB
DB --> Types
```

图表来源
- [src/components/views/schedule-view.tsx:160-513](file://src/components/views/schedule-view.tsx#L160-L513)
- [src/hooks/use-cron-tasks.ts:47-115](file://src/hooks/use-cron-tasks.ts#L47-L115)
- [src/hooks/use-task-executions.ts:30-98](file://src/hooks/use-task-executions.ts#L30-L98)
- [src/app/api/cron-tasks/route.ts:1-53](file://src/app/api/cron-tasks/route.ts#L1-L53)
- [src/app/api/cron-tasks/[id]/route.ts](file://src/app/api/cron-tasks/[id]/route.ts#L1-L66)
- [src/app/api/cron-tasks/[id]/execute/route.ts](file://src/app/api/cron-tasks/[id]/execute/route.ts#L1-L39)
- [src/app/api/cron-engine/route.ts:1-30](file://src/app/api/cron-engine/route.ts#L1-L30)
- [src/app/api/task-executions/route.ts:1-75](file://src/app/api/task-executions/route.ts#L1-L75)
- [src/lib/cron/engine.ts:16-120](file://src/lib/cron/engine.ts#L16-L120)
- [src/lib/cron/cron-parser.ts:7-57](file://src/lib/cron/cron-parser.ts#L7-L57)
- [src/lib/cron/executor.ts:26-306](file://src/lib/cron/executor.ts#L26-L306)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)
- [src/lib/types.ts:162-221](file://src/lib/types.ts#L162-L221)

章节来源
- [src/components/views/schedule-view.tsx:160-513](file://src/components/views/schedule-view.tsx#L160-L513)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)

## 核心组件
- CronEngine 单例：负责定时扫描、并发控制、执行记录与一次性任务自动禁用
- Cron 匹配器：将 cron 表达式按字段拆解并逐位匹配当前时间
- 任务执行器：根据任务类型（心跳、代理、技能、自定义提示）执行并生成会话
- API 路由：提供任务 CRUD、立即执行、引擎启停、执行历史查询
- React Hooks：封装前端状态、任务列表与执行历史加载
- 数据库：SQLite 存储任务、执行记录、会话与消息等

章节来源
- [src/lib/cron/engine.ts:16-120](file://src/lib/cron/engine.ts#L16-L120)
- [src/lib/cron/cron-parser.ts:7-57](file://src/lib/cron/cron-parser.ts#L7-L57)
- [src/lib/cron/executor.ts:26-306](file://src/lib/cron/executor.ts#L26-L306)
- [src/app/api/cron-tasks/route.ts:1-53](file://src/app/api/cron-tasks/route.ts#L1-L53)
- [src/app/api/cron-engine/route.ts:1-30](file://src/app/api/cron-engine/route.ts#L1-L30)
- [src/hooks/use-cron-tasks.ts:47-115](file://src/hooks/use-cron-tasks.ts#L47-L115)
- [src/hooks/use-task-executions.ts:30-98](file://src/hooks/use-task-executions.ts#L30-L98)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)

## 架构总览
调度器采用“单实例引擎 + 外部 API 控制”的模式，前端通过 Hook 与 API 交互，后端引擎在后台以固定周期扫描任务并执行。

```mermaid
sequenceDiagram
participant UI as "ScheduleView"
participant Hook as "useCronTasks/useTaskExecutions"
participant API as "Next.js API 路由"
participant Eng as "CronEngine"
participant Par as "Cron 匹配器"
participant Exec as "任务执行器"
participant DB as "SQLite 数据库"
UI->>Hook : 加载任务/执行历史
Hook->>API : GET /api/cron-tasks /api/task-executions
API->>DB : 查询任务/执行记录
DB-->>API : 返回数据
API-->>Hook : JSON 响应
Hook-->>UI : 渲染任务表与历史
Note over Eng : 后台定时器每分钟触发一次
Eng->>DB : 查询启用的任务
Eng->>Par : 匹配当前时间
Par-->>Eng : 匹配结果
Eng->>Eng : 并发去重(正在执行集合)
Eng->>Exec : 执行任务
Exec->>DB : 创建会话/写入消息
Exec-->>Eng : 返回状态与结果
Eng->>DB : 写入执行记录/更新任务
```

图表来源
- [src/lib/cron/engine.ts:44-105](file://src/lib/cron/engine.ts#L44-L105)
- [src/lib/cron/cron-parser.ts:7-20](file://src/lib/cron/cron-parser.ts#L7-L20)
- [src/lib/cron/executor.ts:26-253](file://src/lib/cron/executor.ts#L26-L253)
- [src/app/api/cron-tasks/route.ts:6-21](file://src/app/api/cron-tasks/route.ts#L6-L21)
- [src/app/api/task-executions/route.ts:5-49](file://src/app/api/task-executions/route.ts#L5-L49)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)

## 详细组件分析

### CronEngine：定时扫描与执行编排
- 启动/停止：首次使用时自动启动；若存在启用任务则自动启动；支持外部启停 API
- 定时策略：启动后立即执行一次，随后每 60 秒执行一次 tick
- 并发控制：使用 Set 记录正在执行的任务 ID，避免重复执行
- 任务筛选：仅扫描 enabled 的任务
- 执行记录：成功/失败均写入 task_executions，并更新任务 last_run_at 与 last_run_result
- 一次性任务：当 cron 的日与月字段为具体值时，执行后自动禁用该任务

```mermaid
flowchart TD
Start(["tick() 触发"]) --> Load["读取启用任务"]
Load --> ForEach{"遍历每个任务"}
ForEach --> |跳过| Next["下一个任务"]
ForEach --> Check["matchesCron() 匹配"]
Check --> |不匹配| Next
Check --> |匹配且未执行| Exec["加入执行集合并执行"]
Exec --> Record["写入执行记录/更新任务"]
Record --> MaybeDisable{"是否一次性任务"}
MaybeDisable --> |是| Disable["设置 enabled=0"]
MaybeDisable --> |否| EndTick["结束本轮"]
Exec --> Done["从执行集合移除"]
Done --> EndTick
```

图表来源
- [src/lib/cron/engine.ts:44-105](file://src/lib/cron/engine.ts#L44-L105)
- [src/lib/cron/cron-parser.ts:7-20](file://src/lib/cron/cron-parser.ts#L7-L20)

章节来源
- [src/lib/cron/engine.ts:16-120](file://src/lib/cron/engine.ts#L16-L120)

### Cron 匹配器：表达式解析与字段匹配
- 支持格式：分钟 小时 日期 月份 星期（共 5 个字段）
- 字段规则：
  - 通配符：*
  - 步长：*/N 或范围-N/M
  - 范围：N-M
  - 枚举：逗号分隔的多个值
- 匹配逻辑：将当前时间映射到对应字段，逐字段验证，全部满足才视为匹配

章节来源
- [src/lib/cron/cron-parser.ts:7-57](file://src/lib/cron/cron-parser.ts#L7-L57)

### 任务执行器：动作类型与通知
- 心跳任务：读取工作区内的 HEARTBEAT.md 检查清单，执行后根据结果发送 IM 通知
- 运行代理：加载代理文件（优先项目内再回退全局），构造系统提示与用户消息
- 运行技能：加载技能文件内容作为系统提示，执行后可选通知
- 自定义提示：直接使用任务 action 作为用户消息，执行后可选通知
- 会话持久化：为每次执行创建会话与消息记录，便于在聊天界面查看
- IM 通知：通过桥接层与适配器向绑定的聊天通道投递消息

```mermaid
sequenceDiagram
participant Eng as "CronEngine"
participant Exec as "executeTask()"
participant WS as "工作区文件系统"
participant SDK as "Claude Agent SDK"
participant IM as "IM 桥接层"
Eng->>Exec : 传入任务行
Exec->>WS : 读取代理/技能/HEARTBEAT 文件
Exec->>SDK : 创建会话并流式执行
SDK-->>Exec : 文本块累积
Exec->>WS : 写入用户/助手消息
Exec->>IM : 可选发送通知
Exec-->>Eng : 返回状态/结果/会话ID
```

图表来源
- [src/lib/cron/executor.ts:26-253](file://src/lib/cron/executor.ts#L26-L253)
- [src/lib/cron/executor.ts:261-297](file://src/lib/cron/executor.ts#L261-L297)

章节来源
- [src/lib/cron/executor.ts:26-306](file://src/lib/cron/executor.ts#L26-L306)

### API 路由与生命周期管理
- 任务管理：
  - GET /api/cron-tasks：按工作区返回任务，包含全局心跳任务
  - POST /api/cron-tasks：创建任务，若引擎未运行则自动启动
  - PATCH /api/cron-tasks/[id]：更新任务，启用时可触发自动启动
  - DELETE /api/cron-tasks/[id]：删除任务（心跳任务不可删）
  - POST /api/cron-tasks/[id]/execute：立即执行某任务
- 引擎控制：
  - GET /api/cron-engine：查询引擎运行状态
  - POST /api/cron-engine：启动或停止引擎
- 执行历史：
  - GET /api/task-executions：分页查询执行记录，支持按工作区、类型、状态过滤

章节来源
- [src/app/api/cron-tasks/route.ts:1-53](file://src/app/api/cron-tasks/route.ts#L1-L53)
- [src/app/api/cron-tasks/[id]/route.ts](file://src/app/api/cron-tasks/[id]/route.ts#L1-L66)
- [src/app/api/cron-tasks/[id]/execute/route.ts](file://src/app/api/cron-tasks/[id]/execute/route.ts#L1-L39)
- [src/app/api/cron-engine/route.ts:1-30](file://src/app/api/cron-engine/route.ts#L1-L30)
- [src/app/api/task-executions/route.ts:1-75](file://src/app/api/task-executions/route.ts#L1-L75)

### 前端视图与交互
- ScheduleView：提供任务列表、执行历史、心跳配置与引擎启停按钮
- useCronTasks：封装任务 CRUD、立即执行与心跳任务查找
- useTaskExecutions：分页加载执行历史，支持类型与状态过滤
- 可视化频率到 cron 表达式的转换：支持一次性、分钟级、小时级、每日、每周、每月

章节来源
- [src/components/views/schedule-view.tsx:160-513](file://src/components/views/schedule-view.tsx#L160-L513)
- [src/hooks/use-cron-tasks.ts:47-115](file://src/hooks/use-cron-tasks.ts#L47-L115)
- [src/hooks/use-task-executions.ts:30-98](file://src/hooks/use-task-executions.ts#L30-L98)

## 依赖关系分析
- CronEngine 依赖：
  - 数据库：查询任务、写入执行记录、更新任务
  - 匹配器：字段级时间匹配
  - 执行器：实际执行动作
- API 路由依赖：
  - CronEngine：引擎启停
  - 数据库：任务与执行记录存取
- 前端 Hook 依赖：
  - API 路由：任务与执行历史
  - 类型定义：强类型约束

```mermaid
graph LR
Engine["CronEngine"] --> Parser["Cron 匹配器"]
Engine --> Executor["任务执行器"]
Engine --> DB["SQLite"]
Executor --> DB
APITasks["/api/cron-tasks"] --> Engine
APIById["/api/cron-tasks/[id]"] --> Engine
APIExecute["/api/cron-tasks/[id]/execute"] --> Executor
APIEngine["/api/cron-engine"] --> Engine
APIExecList["/api/task-executions"] --> DB
DB --> Types["类型定义"]
```

图表来源
- [src/lib/cron/engine.ts:6-10](file://src/lib/cron/engine.ts#L6-L10)
- [src/lib/cron/cron-parser.ts:1-10](file://src/lib/cron/cron-parser.ts#L1-L10)
- [src/lib/cron/executor.ts:6-12](file://src/lib/cron/executor.ts#L6-L12)
- [src/app/api/cron-tasks/route.ts:1-5](file://src/app/api/cron-tasks/route.ts#L1-L5)
- [src/app/api/cron-engine/route.ts:1-5](file://src/app/api/cron-engine/route.ts#L1-L5)
- [src/app/api/task-executions/route.ts:1-5](file://src/app/api/task-executions/route.ts#L1-L5)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)
- [src/lib/types.ts:162-221](file://src/lib/types.ts#L162-L221)

章节来源
- [src/lib/cron/engine.ts:16-120](file://src/lib/cron/engine.ts#L16-L120)
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)

## 性能考虑
- 调度精度与开销
  - 固定周期：每 60 秒扫描一次，适合中小规模任务集
  - 并发控制：正在执行集合避免重复执行，降低资源浪费
- 数据库优化
  - WAL 模式：提升并发读写性能
  - 外键约束：保证数据一致性
  - 索引：task_executions 上按任务与时间排序的复合索引，加速历史查询
- 内存与并发
  - 单例引擎避免多实例竞争
  - 执行集合仅保存任务 ID，内存占用低
- I/O 与网络
  - 任务执行涉及外部 SDK 流式输出，注意背压与超时
  - IM 通知需检查桥接连接状态，避免阻塞主流程

章节来源
- [src/lib/db.ts:22-23](file://src/lib/db.ts#L22-L23)
- [src/lib/db.ts:146-146](file://src/lib/db.ts#L146-L146)
- [src/lib/cron/engine.ts:17-19](file://src/lib/cron/engine.ts#L17-L19)
- [src/lib/cron/engine.ts:54-60](file://src/lib/cron/engine.ts#L54-L60)

## 故障排除指南
- 引擎未运行
  - 现象：任务不触发
  - 排查：调用 GET /api/cron-engine 检查状态；必要时 POST /api/cron-engine 启动
- 任务未匹配
  - 现象：任务未执行
  - 排查：确认任务 enabled 为真；核对 schedule 是否符合 cron 语法；使用可视化频率转换工具校验
- 执行记录缺失
  - 现象：执行历史为空
  - 排查：确认 /api/task-executions 参数（workspace_id、type、status、limit、offset）；检查数据库索引是否生效
- 心跳任务异常
  - 现象：心跳未执行或无通知
  - 排查：确认 HEARTBEAT.md 是否存在且非空；检查 notify_channel 绑定；查看执行记录中的状态与结果
- 一次性任务未禁用
  - 现象：重复执行
  - 排查：确认 cron 的日与月字段是否为具体数值；检查执行后是否更新 enabled 字段

章节来源
- [src/app/api/cron-engine/route.ts:4-29](file://src/app/api/cron-engine/route.ts#L4-L29)
- [src/app/api/task-executions/route.ts:5-49](file://src/app/api/task-executions/route.ts#L5-L49)
- [src/lib/cron/engine.ts:84-89](file://src/lib/cron/engine.ts#L84-L89)

## 结论
该调度器以简洁的单例引擎为核心，结合前端可视化与 API 控制，实现了稳定、可观测的任务调度能力。其优势在于：
- 易于部署与维护：单文件引擎 + SQLite 存储
- 可观测性强：执行记录与会话持久化，便于追踪
- 可扩展性好：任务类型可扩展，通知通道可插拔

建议在大规模场景下引入更细粒度的调度策略（如多线程并发、任务分片）与更丰富的监控指标。

## 附录

### 配置参数与字段说明
- 任务表（cron_tasks）
  - id/name/schedule/action/action_type/agent_name/skill_name/workspace_id/enabled/is_heartbeat/config/last_run_at/last_run_result/created_at/updated_at
- 执行记录表（task_executions）
  - id/task_id/task_name/result/status/session_id/executed_at
- 类型定义
  - CronTaskRow/CronTask/TaskExecution/TaskExecutionStatus/TaskActionType

章节来源
- [src/lib/db.ts:117-146](file://src/lib/db.ts#L117-L146)
- [src/lib/types.ts:162-221](file://src/lib/types.ts#L162-L221)

### 调试方法
- 查看引擎状态：GET /api/cron-engine
- 手动启停引擎：POST /api/cron-engine {"action":"start|stop"}
- 立即执行任务：POST /api/cron-tasks/[id]/execute
- 导出执行历史：GET /api/task-executions?workspace_id=...&type=...&status=...&limit=...&offset=...
- 前端刷新：使用 Hook 的 refresh 方法或页面重新加载

章节来源
- [src/app/api/cron-engine/route.ts:1-30](file://src/app/api/cron-engine/route.ts#L1-L30)
- [src/app/api/cron-tasks/[id]/execute/route.ts](file://src/app/api/cron-tasks/[id]/execute/route.ts#L1-L39)
- [src/app/api/task-executions/route.ts:1-75](file://src/app/api/task-executions/route.ts#L1-L75)
- [src/hooks/use-cron-tasks.ts:107-112](file://src/hooks/use-cron-tasks.ts#L107-L112)
- [src/hooks/use-task-executions.ts:47-83](file://src/hooks/use-task-executions.ts#L47-L83)