baa-conductor

git clone 

baa-conductor / tasks
codex@macbookpro  ·  2026-04-01

T-S064.md

  1# Task T-S064:timed-jobs 异步日志写入
  2
  3## 状态
  4
  5- 当前状态:`已完成`
  6- 规模预估:`S`
  7- 依赖任务:无
  8- 建议执行者:`Codex`
  9
 10## 直接给对话的提示词
 11
 12`/Users/george/code/baa-conductor/tasks/T-S064.md` 任务文档,完成开发任务。
 13
 14如需补背景,再读:
 15
 16- `/Users/george/code/baa-conductor/bugs/OPT-008-timed-jobs-async-log-writes.md`
 17- `/Users/george/code/baa-conductor/tasks/T-S057.md`
 18
 19## 当前基线
 20
 21- 仓库:`/Users/george/code/baa-conductor`
 22- 分支基线:`main`
 23- 提交:`64d122e`
 24
 25## 分支与 worktree(强制)
 26
 27- 分支名:`feat/timed-jobs-async-log-writes`
 28- worktree 路径:`/Users/george/code/baa-conductor-timed-jobs-async-log-writes`
 29
 30开工步骤:
 31
 321. `cd /Users/george/code/baa-conductor`
 332. `git worktree add ../baa-conductor-timed-jobs-async-log-writes -b feat/timed-jobs-async-log-writes main`
 343. `cd ../baa-conductor-timed-jobs-async-log-writes`
 354. 在这个 worktree 目录里开发,不要回到主仓库目录
 36
 37完成后提交与推送:
 38
 391. 在 worktree 里提交所有变更(包括更新后的任务文档)
 402. `git push -u origin feat/timed-jobs-async-log-writes`
 41
 42合并步骤(由合并者执行):
 43
 441. `cd /Users/george/code/baa-conductor`
 452. `git fetch origin`
 463. `git merge origin/feat/timed-jobs-async-log-writes`
 474. `git push`
 485. `git worktree remove ../baa-conductor-timed-jobs-async-log-writes`(如果 worktree 还在)
 49
 50合并冲突处理:
 51
 521. 如果 `git merge` 报冲突,先 `git diff` 查看冲突文件
 532. 手动解决冲突后 `git add` 冲突文件
 543. `git merge --continue` 完成合并
 554. 不要用 `git merge --abort` 然后 force 覆盖
 56
 57命名规则:
 58
 59- 功能任务分支名以 `feat/` 开头
 60- 缺陷任务分支名以 `bug/` 开头
 61
 62## 目标
 63
 64把 timed-jobs JSONL 日志从同步写改成异步写,减少事件循环阻塞。
 65
 66## 背景
 67
 68timed-jobs 已经是正式主链能力。继续使用同步日志写入会放大 tick 周期内的阻塞和抖动,已经不只是“代码风格优化”。
 69
 70## 涉及仓库
 71
 72- `/Users/george/code/baa-conductor`
 73
 74## 范围
 75
 76- timed-jobs runtime 日志写入改异步
 77- 保持日志格式和现有可读性
 78- 补测试或验证
 79
 80## 允许修改的目录
 81
 82- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/timed-jobs/`
 83- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js`
 84
 85## 必须完成
 86
 87### 1. 日志写入改造
 88
 89- 替换同步 `appendFileSync`
 90- 保持单条 JSONL 格式不变
 91- 错误写入不应拖死主链
 92
 93### 2. 行为保持
 94
 95- runner/tick 日志语义保持不变
 96- 不引入明显日志丢失或测试 flake
 97
 98## 验收标准
 99
100- timed-jobs 不再依赖同步日志写入
101- 现有日志仍可直接 tail / 分析
102- 测试覆盖或验证通过
103
104## 推荐验证命令
105
106- `cd /Users/george/code/baa-conductor-timed-jobs-async-log-writes && pnpm -C apps/conductor-daemon test`
107
108## 执行记录
109
110> 以下内容由执行任务的 AI 填写,创建任务时留空。
111
112### 开始执行
113
114- 执行者:`Codex`
115- 开始时间:`2026-04-01 11:29:12 CST`
116- 状态变更:`待开始` → `进行中`
117
118### 完成摘要
119
120- 完成时间:`2026-04-01 11:59:04 CST`
121- 状态变更:`进行中` → `已完成`
122- 修改了哪些文件:
123  - `apps/conductor-daemon/src/timed-jobs/runtime.ts`
124  - `apps/conductor-daemon/src/index.test.js`
125  - `tasks/T-S064.md`
126- 核心实现思路:
127  - 将 timed-jobs JSONL 写入从同步 `appendFileSync` 改为异步追加队列,保持单行 JSONL 格式不变,同时保证同一进程内日志顺序稳定
128  - `runTick` / runner 主流程不等待日志 IO,避免在 tick 热路径上做同步磁盘写;`stop()` 阶段显式 drain 队列,降低停机时日志丢失和测试 flake 风险
129  - 补充测试覆盖“异步写入不阻塞 tick、stop 会等待日志落盘”,并把直接读取 timed-jobs 日志的现有用例改为等待目标日志事件真正落盘后再断言
130- 跑了哪些测试:
131  - `cd /Users/george/code/baa-conductor-timed-jobs-async-log-writes && pnpm install`
132  - `cd /Users/george/code/baa-conductor-timed-jobs-async-log-writes/apps/conductor-daemon && pnpm run build && node --test --test-name-pattern='renewal projector scans settled messages with cursor semantics and skips ineligible conversations' src/index.test.js`
133  - `cd /Users/george/code/baa-conductor-timed-jobs-async-log-writes && pnpm -C apps/conductor-daemon test`
134
135### 执行过程中遇到的问题
136
137- 任务卡记录的基线提交是 `64d122e`,但实际开工时 `origin/main` 已前进到 `37bf1d0`;本次按“从最新 main 开工”的要求创建了 worktree 和分支
138- 新 worktree 初始没有安装依赖,第一次跑测试失败于 `pnpm exec tsc` 不存在;补跑 `pnpm install` 后恢复正常构建与测试流程
139- 日志改成异步写后,旧测试里“先删临时目录再结束 timed-jobs”与“日志一出现就立刻断言目标事件”这两类隐含同步假设会失效;已调整为等待日志落盘并在清理前先 `stop()` drain
140
141### 剩余风险
142
143- `stop()` 正常路径现在会等待日志队列写完,但如果进程被外部强杀,最后少量排队中的日志仍可能来不及落盘