修复: spawn panic 兜底 + namespace 淘汰提示 + run_command 超时与破坏命令信任门控
This commit is contained in:
@@ -270,7 +270,21 @@ pub async fn run_workflow_inner(
|
||||
// F-260616-06 ②-2: move task_id / target_status 进闭包供完成/失败回调使用
|
||||
let cb_task_id = task_id.clone();
|
||||
let cb_target_status = target_status.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
// panic-guard:执行 spawn 闭包最外层包 catch_unwind(AssertUnwindSafe(..))。
|
||||
// panic 时走已存在 failed 分支(update status=failed + emit WorkflowFailed + state_registry.remove),
|
||||
// 防 panic 后终态不发/registry 不清永久卡。主逻辑/调度零改动,仅在 panic 时补发终态。
|
||||
// 注:依赖 panic=unwind(tokio 默认),若构建设 panic=abort 则 catch_unwind 不生效(尽力兜底)。
|
||||
tauri::async_runtime::spawn({
|
||||
// panic 兜底需要这些引用:move 进 catch_unwind 闭包前各取一份 clone 供 panic 分支使用。
|
||||
let panic_exec_id = exec_id.clone();
|
||||
let panic_db = db.clone();
|
||||
let panic_event_bus = event_bus.clone();
|
||||
let panic_registry = state_registry.clone();
|
||||
async move {
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use futures::FutureExt;
|
||||
// 原闭包主体包进 catch_unwind:panic 以 Err(Box<dyn Any>) 返回,Ok 走正常路径。
|
||||
let outcome = AssertUnwindSafe(async move {
|
||||
let mut executor = DagExecutor::new(event_bus.clone(), exec_id.clone());
|
||||
// 注册执行器状态机:StateMachine 内部 Arc<Mutex>,clone 共享底层 HashMap,
|
||||
// cancel_workflow_node IPC 经 execution_id 取此引用 set_cancelled,直达运行中 HumanNode
|
||||
@@ -364,6 +378,46 @@ pub async fn run_workflow_inner(
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}) // 闭 catch_unwind 内 async move
|
||||
.catch_unwind()
|
||||
.await;
|
||||
|
||||
// panic 分支:catch_unwind 返回 Err(Box<dyn Any + Send>),走已存在 failed 清理路径。
|
||||
match outcome {
|
||||
Ok(_) => {}
|
||||
Err(panic_payload) => {
|
||||
// 提取 panic 消息(String/&'static str 常见,其他类型用兜底文案)
|
||||
let msg = panic_payload
|
||||
.downcast_ref::<String>()
|
||||
.map(|s| s.clone())
|
||||
.or_else(|| panic_payload.downcast_ref::<&'static str>().map(|s| s.to_string()))
|
||||
.unwrap_or_else(|| "工作流执行 panic".to_string());
|
||||
tracing::error!(
|
||||
execution_id = %panic_exec_id,
|
||||
"工作流执行 panic,走 failed 分支兜底: {}",
|
||||
msg
|
||||
);
|
||||
let workflows = WorkflowRepo::new(&panic_db);
|
||||
if let Err(e) = workflows.update_field(&panic_exec_id, "status", "failed").await {
|
||||
tracing::error!("更新工作流状态失败(panic 兜底): {}", e);
|
||||
}
|
||||
if let Err(e) = workflows
|
||||
.update_field(&panic_exec_id, "completed_at", &now_millis())
|
||||
.await
|
||||
{
|
||||
tracing::error!("更新工作流完成时间失败(panic 兜底): {}", e);
|
||||
}
|
||||
panic_registry.lock().await.remove(&panic_exec_id);
|
||||
panic_event_bus
|
||||
.send(WorkflowEvent::WorkflowFailed {
|
||||
execution_id: panic_exec_id.clone(),
|
||||
error: msg,
|
||||
failed_node: String::new(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(execution_id.to_string())
|
||||
|
||||
Reference in New Issue
Block a user