use async_trait::async_trait; use chrono::{DateTime, FixedOffset}; use serde_json::Value; use tokio::sync::mpsc::Sender; use crate::flow::context::StreamEvent; use crate::services::flow_run_log_service::{self, CreateRunLogInput}; use crate::db::Db; /// 流程执行日志处理器抽象接口 #[async_trait] pub trait FlowLogHandler: Send + Sync { /// 记录流程开始执行 async fn log_start(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, operator: Option<(i64, String)>) -> anyhow::Result<()>; /// 记录流程执行失败(仅包含错误信息) async fn log_error(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, error_msg: &str, operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()>; /// 记录流程执行失败(包含部分输出与累计日志) async fn log_error_detail(&self, _flow_id: i64, _flow_code: Option<&str>, _input: &Value, _output: &Value, _logs: &[String], error_msg: &str, _operator: Option<(i64, String)>, _started_at: DateTime, _duration_ms: i64) -> anyhow::Result<()> { // 默认实现:退化为仅错误信息 self.log_error(_flow_id, _flow_code, _input, error_msg, _operator, _started_at, _duration_ms).await } /// 记录流程执行成功 async fn log_success(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, output: &Value, logs: &[String], operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()>; /// 推送节点执行事件(仅SSE实现需要) async fn emit_node_event(&self, _node_id: &str, _event_type: &str, _data: &Value) -> anyhow::Result<()> { // 默认空实现,数据库日志处理器不需要 Ok(()) } /// 推送完成事件(仅SSE实现需要) async fn emit_done(&self, _success: bool, _output: &Value, _logs: &[String]) -> anyhow::Result<()> { // 默认空实现,数据库日志处理器不需要 Ok(()) } } /// 数据库日志处理器 pub struct DatabaseLogHandler { db: Db, } impl DatabaseLogHandler { pub fn new(db: Db) -> Self { Self { db } } } #[async_trait] impl FlowLogHandler for DatabaseLogHandler { async fn log_start(&self, _flow_id: i64, _flow_code: Option<&str>, _input: &Value, _operator: Option<(i64, String)>) -> anyhow::Result<()> { // 数据库日志处理器不需要记录开始事件,只在结束时记录 Ok(()) } async fn log_error(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, error_msg: &str, operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: None, ok: false, logs: Some(error_msg.to_string()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create error log: {}", e))?; Ok(()) } async fn log_error_detail(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, output: &Value, logs: &[String], error_msg: &str, operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); // 将 error_msg 附加到日志尾部(若最后一条不同),确保日志中有清晰的错误描述且不重复 let mut all_logs = logs.to_vec(); if all_logs.last().map(|s| s != error_msg).unwrap_or(true) { all_logs.push(error_msg.to_string()); } flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: Some(serde_json::to_string(output).unwrap_or_default()), ok: false, logs: Some(serde_json::to_string(&all_logs).unwrap_or_default()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create error log with details: {}", e))?; Ok(()) } async fn log_success(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, output: &Value, logs: &[String], operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: Some(serde_json::to_string(output).unwrap_or_default()), ok: true, logs: Some(serde_json::to_string(logs).unwrap_or_default()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create success log: {}", e))?; Ok(()) } } /// SSE日志处理器 pub struct SseLogHandler { db: Db, event_tx: Sender, } impl SseLogHandler { pub fn new(db: Db, event_tx: Sender) -> Self { Self { db, event_tx } } } #[async_trait] impl FlowLogHandler for SseLogHandler { async fn log_start(&self, _flow_id: i64, _flow_code: Option<&str>, _input: &Value, _operator: Option<(i64, String)>) -> anyhow::Result<()> { // SSE处理器也不需要记录开始事件 Ok(()) } async fn log_error(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, error_msg: &str, operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { // 先推送SSE错误事件(不在此处发送 done,交由调用方统一携带 ctx/logs 发送) crate::middlewares::sse::emit_error(&self.event_tx, error_msg.to_string()).await; // 然后记录到数据库(仅错误信息) let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: None, ok: false, logs: Some(error_msg.to_string()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create error log: {}", e))?; Ok(()) } async fn log_error_detail(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, output: &Value, logs: &[String], error_msg: &str, operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { // 先推送SSE错误事件(不在此处发送 done,交由调用方统一携带 ctx/logs 发送) crate::middlewares::sse::emit_error(&self.event_tx, error_msg.to_string()).await; // 然后记录到数据库(包含部分输出与累计日志),避免重复附加相同错误信息 let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); let mut all_logs = logs.to_vec(); if all_logs.last().map(|s| s != error_msg).unwrap_or(true) { all_logs.push(error_msg.to_string()); } flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: Some(serde_json::to_string(output).unwrap_or_default()), ok: false, logs: Some(serde_json::to_string(&all_logs).unwrap_or_default()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create error log with details: {}", e))?; Ok(()) } async fn log_success(&self, flow_id: i64, flow_code: Option<&str>, input: &Value, output: &Value, logs: &[String], operator: Option<(i64, String)>, started_at: DateTime, duration_ms: i64) -> anyhow::Result<()> { // 先推送SSE完成事件 crate::middlewares::sse::emit_done(&self.event_tx, true, output.clone(), logs.to_vec()).await; // 然后记录到数据库 let (user_id, username) = operator.map(|(u, n)| (Some(u), Some(n))).unwrap_or((None, None)); flow_run_log_service::create(&self.db, CreateRunLogInput { flow_id, flow_code: flow_code.map(|s| s.to_string()), input: Some(serde_json::to_string(input).unwrap_or_default()), output: Some(serde_json::to_string(output).unwrap_or_default()), ok: true, logs: Some(serde_json::to_string(logs).unwrap_or_default()), user_id, username, started_at, duration_ms, }).await.map_err(|e| anyhow::anyhow!("Failed to create success log: {}", e))?; Ok(()) } async fn emit_node_event(&self, node_id: &str, event_type: &str, data: &Value) -> anyhow::Result<()> { // 推送节点事件到SSE let event = StreamEvent::Node { node_id: node_id.to_string(), logs: vec![event_type.to_string()], ctx: data.clone(), }; if let Err(_e) = self.event_tx.send(event).await { // 通道可能已关闭,忽略错误 } Ok(()) } async fn emit_done(&self, success: bool, output: &Value, logs: &[String]) -> anyhow::Result<()> { crate::middlewares::sse::emit_done(&self.event_tx, success, output.clone(), logs.to_vec()).await; Ok(()) } }