feat: status_reason field for workflows + proper failure logging
- Add status_reason column to workflows table (migration) - AgentUpdate::WorkflowStatus and WorkflowComplete carry reason - Dispatch failure logs to execution_log with reason - Worker disconnect marks orphaned workflows as failed with reason - All status transitions now have traceable cause
This commit is contained in:
26
src/agent.rs
26
src/agent.rs
@@ -158,15 +158,20 @@ impl AgentManager {
|
||||
tracing::info!("Workflow {} dispatched to worker '{}'", workflow_id, name);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to dispatch workflow {}: {}", workflow_id, e);
|
||||
let _ = sqlx::query("UPDATE workflows SET status = 'failed' WHERE id = ?")
|
||||
.bind(&workflow_id).execute(&self.pool).await;
|
||||
let _ = btx.send(WsMessage::WorkflowStatusUpdate {
|
||||
workflow_id,
|
||||
status: "failed".into(),
|
||||
let reason = format!("调度失败: {}", e);
|
||||
tracing::error!("Failed to dispatch workflow {}: {}", workflow_id, reason);
|
||||
let _ = sqlx::query("UPDATE workflows SET status = 'failed', status_reason = ? WHERE id = ?")
|
||||
.bind(&reason).bind(&workflow_id).execute(&self.pool).await;
|
||||
// Log to execution_log so frontend can show the reason
|
||||
let log_id = uuid::Uuid::new_v4().to_string();
|
||||
let _ = sqlx::query(
|
||||
"INSERT INTO execution_log (id, workflow_id, step_order, tool_name, tool_input, output, status, created_at) VALUES (?, ?, 0, 'system', 'dispatch', ?, 'failed', datetime('now'))"
|
||||
).bind(&log_id).bind(&workflow_id).bind(&reason).execute(&self.pool).await;
|
||||
let _ = btx.send(WsMessage::StepStatusUpdate {
|
||||
step_id: log_id, status: "failed".into(), output: reason,
|
||||
});
|
||||
let _ = btx.send(WsMessage::Error {
|
||||
message: format!("No worker available: {}", e),
|
||||
let _ = btx.send(WsMessage::WorkflowStatusUpdate {
|
||||
workflow_id, status: "failed".into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -745,6 +750,7 @@ pub async fn run_step_loop(
|
||||
let _ = update_tx.send(AgentUpdate::WorkflowStatus {
|
||||
workflow_id: workflow_id.to_string(),
|
||||
status: "waiting_user".into(),
|
||||
reason: String::new(),
|
||||
}).await;
|
||||
send_execution(update_tx, workflow_id, step_order, "ask_user", reason, reason, "waiting").await;
|
||||
|
||||
@@ -789,6 +795,7 @@ pub async fn run_step_loop(
|
||||
let _ = update_tx.send(AgentUpdate::WorkflowStatus {
|
||||
workflow_id: workflow_id.to_string(),
|
||||
status: "executing".into(),
|
||||
reason: String::new(),
|
||||
}).await;
|
||||
|
||||
let tool_msg = if feedback.is_empty() {
|
||||
@@ -1084,6 +1091,7 @@ pub async fn run_agent_loop(
|
||||
let _ = update_tx.send(AgentUpdate::WorkflowStatus {
|
||||
workflow_id: workflow_id.to_string(),
|
||||
status: "waiting_user".into(),
|
||||
reason: String::new(),
|
||||
}).await;
|
||||
send_execution(update_tx, workflow_id, 0, "plan_approval", "等待确认计划", "等待用户确认执行计划", "waiting").await;
|
||||
|
||||
@@ -1114,6 +1122,7 @@ pub async fn run_agent_loop(
|
||||
let _ = update_tx.send(AgentUpdate::WorkflowStatus {
|
||||
workflow_id: workflow_id.to_string(),
|
||||
status: "executing".into(),
|
||||
reason: String::new(),
|
||||
}).await;
|
||||
// Stay in Planning phase, continue the loop
|
||||
continue;
|
||||
@@ -1130,6 +1139,7 @@ pub async fn run_agent_loop(
|
||||
let _ = update_tx.send(AgentUpdate::WorkflowStatus {
|
||||
workflow_id: workflow_id.to_string(),
|
||||
status: "executing".into(),
|
||||
reason: String::new(),
|
||||
}).await;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user