74 lines
4.0 KiB
Markdown
74 lines
4.0 KiB
Markdown
# 自动化任务调度机制(09-01 定稿,实测验证)
|
||||
|
|
|
|||
|
|
> 本文档固化 08-31~09-01 多次调试理清的客户端自动化调度机制,是工作台 `/api/run` 链路唯一权威说明。
|
|||
|
|
> 结论均来自本机实测(automations / automation_runs / sessions 三表 + 调度器实际行为),非推测。
|
|||
|
|
|
|||
|
|
## 一、完整链路
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
工作台按钮 → POST /api/run → 直写 ~/.workbuddy/workbuddy.db automations 表
|
|||
|
|
→ 客户端调度器按 next_run_at 扫描(周期 ≈30s)
|
|||
|
|
→ 命中 → automation_runs 写 QUEUED → 建会话(sessions 表, is_background_automation=1)
|
|||
|
|
→ IN_PROGRESS(meta 含 conversationId/sessionId)→ 执行 → ACCEPTED(含 resultState/resultEvidence)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1 任务 = 1 会话,一一对应。
|
|||
|
|
|
|||
|
|
## 二、根因(必须牢记)
|
|||
|
|
|
|||
|
|
| 现象 | 根因 |
|
|||
|
|
|---|---|
|
|||
|
|
| 工作台任务全卡死、永不执行 | **调度器按 `next_run_at` 列扫描**。工作台直写 SQLite 时若缺/空该列 → 永不拾取(08-31 P2「去掉 next_run_at 用 scheduled_at」是错误判断,09-01 已纠正) |
|
|||
|
|
| `scheduled_at` 写过去时间 → 卡死 | 客户端只对**未来** scheduledAt 自动补算 next_run_at;过去/太近时间 → 不补算 → 扫不到 |
|
|||
|
|
| 误以为「调度器停摆」 | 调度器从未停摆(33022 秒级准点执行过);停摆假象 = next_run_at 没填 |
|
|||
|
|
|
|||
|
|
## 三、硬规则(实测阈值)
|
|||
|
|
|
|||
|
|
1. **scheduled_at 必须未来**,且留足余量:**+60s 稳、+17s 失败**(update 往返有几秒延迟,越近越险)
|
|||
|
|
2. **next_run_at 必须显式写入**(工作台链路):`Date.now() + 5000`(+5s 即可,因为这是直写、无补算依赖)
|
|||
|
|
3. **立即执行参数不存在**:argv.json(仅 IDE 渲染)、settings.json(仅插件/sandbox/claw)、无 workbuddy CLI,客户端无并发数/扫描周期配置项 → 无法通过参数控制
|
|||
|
|
4. 实际开始时间 = 写库时刻 + 5s(next_run_at)+ 扫描周期(≤30s)≈ **5~35s**(工作台按钮链路已是最快路径)
|
|||
|
|
|
|||
|
|
## 四、并发与排队(09-01 实测)
|
|||
|
|
|
|||
|
|
- **客户端后台自动化并发上限 ≈ 3**:同秒触发 5 任务 → 3 个立即并行(各建会话)、2 个排队
|
|||
|
|
- 排队标记:automation_runs.metadata_json 含 `queuedPosition`(1、2、…)
|
|||
|
|
- 并行是任务层面天然支持的,无需任何配置;超出 3 个自动排队
|
|||
|
|
|
|||
|
|
## 五、automation_runs 状态机
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
QUEUED(排队, meta.queuedPosition)
|
|||
|
|
→ IN_PROGRESS(建会话, meta.conversationId/sessionId)
|
|||
|
|
→ ACCEPTED(完成, meta.resultState=delivered|side_effect_only|partial_delivered, resultEvidence=assistant_output|external_action|local_file_mutation|none)
|
|||
|
|
```
|
|||
|
|
另有 PENDING_REVIEW(待人工确认,工作台轮询时显示「待确认」)。
|
|||
|
|
|
|||
|
|
表结构:`thread_id / automation_id / status / read_at / thread_title / source_cwd / runs_json / result_success / metadata_json / created_at / updated_at`
|
|||
|
|
|
|||
|
|
## 六、排查命令(Windows / Git Bash)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd "C:/Users/maidou/.workbuddy"
|
|||
|
|
"D:/miniconda3/python.exe" -c "
|
|||
|
|
import sqlite3
|
|||
|
|
db = sqlite3.connect('workbuddy.db'); db.row_factory = sqlite3.Row
|
|||
|
|
for r in db.execute(\"SELECT id,name,scheduled_at,next_run_at,last_run_at,status FROM automations WHERE deleted_at IS NULL ORDER BY created_at DESC LIMIT 10\"):
|
|||
|
|
print(dict(r))
|
|||
|
|
print('---runs---')
|
|||
|
|
for r in db.execute(\"SELECT automation_id,status,metadata_json FROM automation_runs ORDER BY created_at DESC LIMIT 10\"):
|
|||
|
|
print(dict(r))
|
|||
|
|
"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
判定要点:
|
|||
|
|
- 任务有 `next_run_at` 且 < now → 应已被拾取(看 automation_runs)
|
|||
|
|
- `last_run_at` 仍 None + runs 无记录 → next_run_at 没补算(scheduled_at 太近/过去)
|
|||
|
|
- runs 有 QUEUED → 在排队(并发 >3);有 IN_PROGRESS → 正在跑(看 sessions working)
|
|||
|
|
- 会话:`SELECT id,title,status,created_at FROM sessions WHERE is_background_automation=1`
|
|||
|
|
|
|||
|
|
## 七、服务维护
|
|||
|
|
|
|||
|
|
- 启动:`node server.js`(零依赖,端口 8899 自动避让)
|
|||
|
|
- 改 server.js 后必须重启才生效(Windows:`taskkill /PID <pid> /F` 后重启)
|
|||
|
|
- 后台运行:`node server.js > /tmp/mcn-workshop.log 2>&1 &`
|