一个已登记 RunningTask 最终只能由正常完成路径或显式 abort 路径之一拥有终态。源码没有用一个单独的 terminal_sent 布尔值实现,而是通过 ActiveTurn 所有权转移、CancellationToken 和 task handle detach 构成结构性互斥。
两条终态路径
正常路径中,Task wrapper 得到 run() 结果、flush,并在根 token 未取消时调用 on_task_finished。完成函数在 ActiveTurn 锁内取走 task;若 task 已被 abort 路径取走,得到 None 并直接返回。它随后统计、选择 TurnComplete 或由返回的 TurnAborted error映射 TurnAborted,发送后按 TurnState Arc 身份清 ActiveTurn。
Abort 路径先取走整个 ActiveTurn,所以正常 wrapper 后来即使结束,也因 token cancelled 不调用 finish;即使发生竞态进入 finish,也找不到 task。abort 自己在 handle_task_abort 中发 TurnAborted。
async def task_wrapper(result, token):
await flush_rollout()
if not token.is_cancelled():
await on_task_finished(result)
async def on_task_finished(result):
async with active_turn.lock() as active:
task = active.take_task_if_present()
if task is None:
return # abort 已拥有终态
await emit_one_terminal(map_result(result))
await clear_active_only_if_same_turn_state()
async def abort_all():
active = await take_entire_active_turn()
if active and active.task:
await handle_task_abort(active.task) # 这里发 TurnAborted
task result 的映射
Ok(Some(message)) 和 Ok(None) 都产生 TurnComplete,只是 last_agent_message 不同。Err(CodexErr::TurnAborted) 在自然完成收口中映射成 Interrupted 的 TurnAborted。其他意外错误会 warning;采样期可报告错误通常已经写入 TurnContext.terminal_error 或发 Error event,最终仍用 TurnComplete 携带 error 字段,让客户端得到一个闭合生命周期。
这说明 Error Event 不等于终态。一次 Turn 可以先发 Error,再发 TurnComplete(error=…);客户端应等待 Complete/Aborted,而不是收到任何错误就自行关闭状态机。
Arc 身份检查防止清掉后继任务
on_task_finished 保存本轮 Arc<Mutex<TurnState>>。发送终态后再锁 ActiveTurn,只有当前槽位 task 已为 None 且 Arc::ptr_eq 仍指向这份 TurnState 才设 None。若某条边界路径已安装新的 state,旧完成函数不得清除它。
清理成功后才发 Thread Idle lifecycle、清 guardian circuit breaker并尝试启动 pending work。这样 Idle 表达“当前 ActiveTurn 确实为空”,不是“某个旧 Tokio task 刚返回”。
评论
登录后即可评论