s16:一个并行分支失败后,journal 提前关闭,其他 Agent 的成功结果无法保存
s16:一个并行分支失败后,journal 提前关闭,其他 Agent 的成功结果无法保存
问题
在 main 的 0dcafa2ae053a1ddd6a72f265431104b08a5aa13 上,
ExecutionState.parallel() 和 pipeline() 都使用默认的 asyncio.gather()。
一个分支抛出异常时,gather() 会立即向外抛错,但其他分支仍然在运行。
此时 WorkflowTool._call_locked() 会标记失败、关闭 journal、写入最终快照,
再发送 task_notification 并释放运行锁。其他 Agent 随后返回成功结果时,
会尝试写入已经关闭的 journal,导致结果无法保存。
这会影响本章介绍的断点续跑:已经执行成功的模型调用没有进入缓存,resume 时 可能需要重新调用,最终用量快照也可能遗漏这部分工作。
复现
已在 Linux / Python 3.12 环境中复现,使用受控 runner,不需要 API Key 或真实模型请求。
- 启动一个包含两个并行分支的工作流,让第一个分支等待一个事件。
- 确认第一个分支已经启动后,让第二个分支抛出
RuntimeError。 - 此时第一个分支尚未完成,
WorkflowTool.call()就已经返回失败。 - 放行第一个分支,让它通过现有
MockAgentRunner完成ctx.agent()。 - 该分支写入 journal 时出现
I/O operation on closed file,成功结果没有保存。
原版的复现输出如下:
Finalized before sibling completed: True
Late child errors: ['I/O operation on closed file.']
Saved successful results: 0
Final workflow status: failed
另外,针对 parallel 和 pipeline 补充的两项回归测试,在修复前均失败。
建议修改
让 parallel() 使用 return_exceptions=True,等待已启动的分支结束后,
再抛出其中的异常。pipeline() 复用这一行为,每个 item 仍独立经过各阶段。
这样成功分支可以在 journal 关闭前保存结果,恢复时就能复用。
代价是失败通知需要等待其他分支结束。直接取消等待中的协程并不能停止
asyncio.to_thread() 中已经发出的模型请求,因此这里建议先等待分支结束。
目前已准备最小修复、现有测试文件中的回归用例,以及中英日三语章节说明。 想先确认:这一失败路径是否属于 s16 希望覆盖的教学范围?如果方向合适,再提交关联 PR。
说明:本次使用 Codex 协助分析和准备修改,复现及测试已在本地运行。
Source: shareAI-lab/learn-claude-code