Direct 回合 panic 转成可诊断的分类失败
Project CI / AI game creator shell Rust smoke (push) Failing after 2m4s
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 2m4s
Project CI / AI game creator shell Rust crates (push) Successful in 2m3s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 2m17s
Project CI / Backend tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Failing after 2m4s
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 2m4s
Project CI / AI game creator shell Rust crates (push) Successful in 2m3s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 2m17s
Project CI / Backend tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
dispatch 层用 AssertUnwindSafe/catch_unwind 接住回合体 panic,不再落到 HostDropped 兜底 panic 负载转成直接可读文本并写进脱敏诊断与应用日志,终态改为分类失败 补齐 futures::FutureExt 导入
This commit is contained in:
@@ -13,13 +13,16 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use futures::FutureExt;
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::agent::PendingTurn;
|
||||
use crate::agent::{
|
||||
append_direct_project_user_message_at, claim_pending_turn, complete_turn_if_reserved,
|
||||
direct_codex_user_item_to_prompt, direct_now_ms, redact_agent_runtime_error,
|
||||
run_direct_game_creator_turn_at_with_creation_type_and_emitter, thread_id_for_project,
|
||||
DirectGameCreatorTurnUpdateEmitter, DirectTurnError, DirectTurnTerminal, DispatchedTurn,
|
||||
direct_codex_user_item_to_prompt, direct_now_ms, record_direct_codex_failure,
|
||||
redact_agent_runtime_error, run_direct_game_creator_turn_at_with_creation_type_and_emitter,
|
||||
thread_id_for_project, DirectCodexFailureStage, DirectGameCreatorTurnUpdateEmitter,
|
||||
DirectTurnError, DirectTurnTerminal, DispatchedTurn,
|
||||
};
|
||||
|
||||
/// 一次放行的占用。持有它就代表这一轮还没收口。
|
||||
@@ -184,6 +187,17 @@ pub(crate) fn kick_queue_dispatch(root: &Path) {
|
||||
}));
|
||||
}
|
||||
|
||||
/// 把 panic 负载转成可读文本:`panic!("…")` 的负载是 `&str`,`panic!("{x}")` 是 `String`。
|
||||
fn direct_turn_panic_detail(payload: &(dyn std::any::Any + Send)) -> String {
|
||||
if let Some(text) = payload.downcast_ref::<&str>() {
|
||||
(*text).to_string()
|
||||
} else if let Some(text) = payload.downcast_ref::<String>() {
|
||||
text.clone()
|
||||
} else {
|
||||
"未知 panic 负载".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// 放行之后这一段:取这一轮的调用身份 → 落盘用户条目 → 下发 → 跑整轮。
|
||||
///
|
||||
/// 这一段的每个失败都是**回合失败**:占用与开始事件已经写好,只走占用对象的终态出口,不再回到任何
|
||||
@@ -218,16 +232,38 @@ async fn run_dispatched_direct_turn(
|
||||
crate::agent::codex_app_server::emit_direct_thread_user_item(&root, &canonical_user_item);
|
||||
let capture = crate::analytics::gui::capture_writer_context();
|
||||
let emitter = DirectGameCreatorTurnUpdateEmitter::new(&root, turn_id);
|
||||
let outcome = run_direct_game_creator_turn_at_with_creation_type_and_emitter(
|
||||
&root,
|
||||
&prompt,
|
||||
dispatched.pending.creation_type.as_deref(),
|
||||
Some(&emitter),
|
||||
Some(canonical_user_item.clone()),
|
||||
capture,
|
||||
release_identity_generation,
|
||||
// 回合体 panic 不能落到 `TurnReservation` 的 Drop 兜底:那会把这一轮收成"说不出原因"的
|
||||
// `HostDropped`,症状正是用户看到的「本轮执行已中断,请重试」,而项目侧诊断与应用日志
|
||||
// **一行都不会有**(真实案例:2026-10-02 连续两轮)。这里把 panic 转成分类失败,
|
||||
// 走与正常失败同一条收口:先写脱敏诊断,再写终态。
|
||||
let outcome = match std::panic::AssertUnwindSafe(
|
||||
run_direct_game_creator_turn_at_with_creation_type_and_emitter(
|
||||
&root,
|
||||
&prompt,
|
||||
dispatched.pending.creation_type.as_deref(),
|
||||
Some(&emitter),
|
||||
Some(canonical_user_item.clone()),
|
||||
capture,
|
||||
release_identity_generation,
|
||||
),
|
||||
)
|
||||
.await;
|
||||
.catch_unwind()
|
||||
.await
|
||||
{
|
||||
Ok(result) => result,
|
||||
Err(payload) => {
|
||||
let failure = DirectTurnError::turn_failed(
|
||||
DirectCodexFailureStage::CodeGeneration,
|
||||
format!(
|
||||
"DirectProject 宿主任务 panic:{}",
|
||||
direct_turn_panic_detail(payload.as_ref())
|
||||
),
|
||||
);
|
||||
let stage = failure.turn_failure_stage();
|
||||
let detail = record_direct_codex_failure(&root, &failure, Some(turn_id.as_str()));
|
||||
Err(DirectTurnError::TurnFailed { stage, detail })
|
||||
}
|
||||
};
|
||||
match outcome {
|
||||
Ok(_) => {
|
||||
// 深层的终态出口已经在 `run_turn` 里写出 `turn.completed`;这里只补最后一条回合更新。
|
||||
|
||||
Reference in New Issue
Block a user