问题概述
用户停止 workflow 后,agent() 抛出的 WorkflowAbortedError 会被 parallel() 和 pipeline() 的通用 catch 当作普通任务失败处理并转换成 null。控制流异常没有传播到 runWorkflow(),最终运行记录和 run_done 事件都错误地写成 completed。
严重度
严重(High)
- 用户明确取消后,UI、事件流和持久化状态仍显示“已完成”。
- 不完整结果以
[null] 的成功返回值进入下游,可能触发后续自动化。
- 审计、恢复和完成通知都基于错误的终态。
环境
- 代码版本:
3bb6b5746238c418138eb96d57765d79012edd96
- Bun:
1.3.13
- 系统:
Linux 5.15.0-186-generic x86_64
稳定复现
使用预先 abort 的 AbortSignal 分别运行以下脚本(其余参数可复用 packages/workflow-engine/src/__tests__/runWorkflow.test.ts 的测试 ports):
const scripts = {
direct: `return agent('x')`,
parallel: `return parallel([() => agent('x')])`,
pipeline: `return pipeline(['x'], (_prev, item) => agent(item))`,
}
const ac = new AbortController()
ac.abort()
const result = await runWorkflow({
script: scripts.parallel,
signal: ac.signal,
// runId / ports / host / cwd / budgetTotal 使用正常测试值
})
在同一进程内重复运行可稳定得到:
direct result={"status":"killed"}
run_done={"status":"killed"}
parallel warning="parallel thunk #0 failed: workflow has been aborted"
result={"status":"completed","returnValue":[null]}
run_done={"status":"completed","returnValue":[null]}
pipeline warning="pipeline item #0 failed: workflow has been aborted"
result={"status":"completed","returnValue":[null]}
run_done={"status":"completed","returnValue":[null]}
实际行为
直接调用 agent() 时状态为 killed;只要相同调用包进 parallel() 或 pipeline(),状态就变为 completed。
预期行为
WorkflowAbortedError 是整个运行的取消控制流,应穿透组合器并由 runWorkflow() 映射为 killed。普通业务异常仍可保持当前的“记录 warning 并返回 null”契约。
根因
packages/workflow-engine/src/engine/hooks.ts 中:
parallel() 捕获每个 thunk 的全部异常并返回 null;
pipeline() 捕获每条 pipeline 的全部异常并返回 null。
两处都没有排除 WorkflowAbortedError。而 packages/workflow-engine/src/engine/runWorkflow.ts 只有在该异常传播出来时,才会产生 status: 'killed'。
建议修复
在两处 catch 的最前面加入:
if (e instanceof WorkflowAbortedError) throw e
并补充两层回归测试:
- hooks 单元测试断言
parallel / pipeline 会重新抛出取消异常;
runWorkflow 测试断言 result 与最终 run_done 均为 killed,同时保留普通异常转 null 的既有测试。
查重
已检索开放/关闭 issue 和全部 PR,关键词包括 WorkflowAbortedError、parallel abort、pipeline abort、workflow killed completed,未发现同因问题。
问题概述
用户停止 workflow 后,
agent()抛出的WorkflowAbortedError会被parallel()和pipeline()的通用catch当作普通任务失败处理并转换成null。控制流异常没有传播到runWorkflow(),最终运行记录和run_done事件都错误地写成completed。严重度
严重(High)
[null]的成功返回值进入下游,可能触发后续自动化。环境
3bb6b5746238c418138eb96d57765d79012edd961.3.13Linux 5.15.0-186-generic x86_64稳定复现
使用预先 abort 的
AbortSignal分别运行以下脚本(其余参数可复用packages/workflow-engine/src/__tests__/runWorkflow.test.ts的测试 ports):在同一进程内重复运行可稳定得到:
实际行为
直接调用
agent()时状态为killed;只要相同调用包进parallel()或pipeline(),状态就变为completed。预期行为
WorkflowAbortedError是整个运行的取消控制流,应穿透组合器并由runWorkflow()映射为killed。普通业务异常仍可保持当前的“记录 warning 并返回 null”契约。根因
packages/workflow-engine/src/engine/hooks.ts中:parallel()捕获每个 thunk 的全部异常并返回null;pipeline()捕获每条 pipeline 的全部异常并返回null。两处都没有排除
WorkflowAbortedError。而packages/workflow-engine/src/engine/runWorkflow.ts只有在该异常传播出来时,才会产生status: 'killed'。建议修复
在两处
catch的最前面加入:并补充两层回归测试:
parallel/pipeline会重新抛出取消异常;runWorkflow测试断言 result 与最终run_done均为killed,同时保留普通异常转null的既有测试。查重
已检索开放/关闭 issue 和全部 PR,关键词包括
WorkflowAbortedError、parallel abort、pipeline abort、workflow killed completed,未发现同因问题。