diff --git a/sqle/api/controller/v1/workflow.go b/sqle/api/controller/v1/workflow.go index 2d3a3f1b9..79d2fdac9 100644 --- a/sqle/api/controller/v1/workflow.go +++ b/sqle/api/controller/v1/workflow.go @@ -2001,7 +2001,7 @@ func AutoCreateAndExecuteWorkflowV1(c echo.Context) error { } // 11. 执行工单 - workFlowStatus, err := executeWorkflow(projectUid, workflow, user) + workFlowStatus, err := executeWorkflowForAuto(projectUid, workflow, user) if err != nil { return controller.JSONBaseErrorReq(c, err) } @@ -2261,8 +2261,14 @@ func validateBackupForNonDQLSQLs(s *model.Storage, tasks []*model.Task) error { return nil } -// executeWorkflow 执行工单 -func executeWorkflow(projectUid string, workflow *model.Workflow, user *model.User) (string, error) { +// executeWorkflowForAuto 执行自动创建的工单 +// 此函数专门用于自动创建工单的执行流程,与普通工单执行的区别在于: +// - 使用特殊的通知类型(auto_exec_success/auto_exec_failed)来区分自动创建和普通创建的工单 +// - 通过传递 isAutoCreated=true 给 ExecuteTasksProcess,确保 webhook 通知中的 action 字段为 "auto_exec_success" 或 "auto_exec_failed" +// 使用场景: +// - AutoCreateAndExecuteWorkflowV1: 通过工作台执行非DQL类型SQL时自动创建的工单 +// 注意: 此函数不应用于普通工单的执行,普通工单应使用其他执行流程 +func executeWorkflowForAuto(projectUid string, workflow *model.Workflow, user *model.User) (string, error) { needExecTaskIds, err := GetNeedExecTaskIds(workflow, user) if err != nil { return "", err @@ -2272,7 +2278,8 @@ func executeWorkflow(projectUid string, workflow *model.Workflow, user *model.Us return "", nil } - ch, err := server.ExecuteTasksProcess(workflow.WorkflowId, projectUid, user) + // 传递 true 标识这是自动创建的工单,将使用特殊的通知类型 + ch, err := server.ExecuteTasksProcess(workflow.WorkflowId, projectUid, user, true) if err != nil { return "", err } diff --git a/sqle/notification/notification.go b/sqle/notification/notification.go index 63cbb0309..ed31b644d 100644 --- a/sqle/notification/notification.go +++ b/sqle/notification/notification.go @@ -53,6 +53,8 @@ const ( WorkflowNotifyTypeExecuteFail WorkflowNotifyTypeCancel WorkflowNotifyTypeComplete + WorkflowNotifyTypeAutoExecuteSuccess + WorkflowNotifyTypeAutoExecuteFail ) func getWorkflowNotifyTypeAction(wt WorkflowNotifyType) string { @@ -71,6 +73,10 @@ func getWorkflowNotifyTypeAction(wt WorkflowNotifyType) string { return "cancel" case WorkflowNotifyTypeComplete: return "complete" + case WorkflowNotifyTypeAutoExecuteSuccess: + return "auto_exec_success" + case WorkflowNotifyTypeAutoExecuteFail: + return "auto_exec_failed" } return "unknown" } @@ -104,9 +110,9 @@ func (w *WorkflowNotification) NotificationSubject() i18nPkg.I18nStr { return locale.Bundle.LocalizeAllWithArgs(locale.NotifyWorkflowNotifyTypeWaiting, GetWorkflowStepTypeDesc(w.workflow.CurrentStep().Template.Typ)) case WorkflowNotifyTypeReject: return locale.Bundle.LocalizeAll(locale.NotifyWorkflowNotifyTypeReject) - case WorkflowNotifyTypeExecuteSuccess: + case WorkflowNotifyTypeExecuteSuccess, WorkflowNotifyTypeAutoExecuteSuccess: return locale.Bundle.LocalizeAll(locale.NotifyWorkflowNotifyTypeExecuteSuccess) - case WorkflowNotifyTypeExecuteFail: + case WorkflowNotifyTypeExecuteFail, WorkflowNotifyTypeAutoExecuteFail: return locale.Bundle.LocalizeAll(locale.NotifyWorkflowNotifyTypeExecuteFail) case WorkflowNotifyTypeComplete: return locale.Bundle.LocalizeAll(locale.NotifyWorkflowNotifyTypeComplete) @@ -189,7 +195,7 @@ func (w *WorkflowNotification) buildNotifyBody(task *model.Task) i18nPkg.I18nStr res = append(res, locale.Bundle.LocalizeAllWithArgs(locale.NotifyWorkflowBodyInstanceAndSchema, instanceName, schema)) switch w.notifyType { - case WorkflowNotifyTypeExecuteSuccess, WorkflowNotifyTypeExecuteFail: + case WorkflowNotifyTypeExecuteSuccess, WorkflowNotifyTypeExecuteFail, WorkflowNotifyTypeAutoExecuteSuccess, WorkflowNotifyTypeAutoExecuteFail: res = append(res, locale.Bundle.LocalizeAllWithArgs(locale.NotifyWorkflowBodyStartEnd, executeStartAt, executeEndAt)) case WorkflowNotifyTypeReject: var reason string @@ -227,7 +233,7 @@ func (w *WorkflowNotification) notifyUser() []string { w.workflow.CreateUserId, } // if workflow is executed, the creator and executor needs to be notified. - case WorkflowNotifyTypeExecuteSuccess, WorkflowNotifyTypeExecuteFail: + case WorkflowNotifyTypeExecuteSuccess, WorkflowNotifyTypeExecuteFail, WorkflowNotifyTypeAutoExecuteSuccess, WorkflowNotifyTypeAutoExecuteFail: // 获取该工单对应数据源上有工单审核权限的所有用户 auditUsers, err := w.getAuditUsersForWorkflowInstances() if err != nil { diff --git a/sqle/server/workflow_schedule.go b/sqle/server/workflow_schedule.go index 39fd13712..fed1ed14b 100644 --- a/sqle/server/workflow_schedule.go +++ b/sqle/server/workflow_schedule.go @@ -64,7 +64,23 @@ func (j *WorkflowScheduleJob) WorkflowSchedule(entry *logrus.Entry) { } } -func ExecuteWorkflow(workflow *model.Workflow, needExecTaskIdToUserId map[uint]string) (chan string, error) { +// ExecuteWorkflow 执行工单中的任务 +// 参数说明: +// - workflow: 要执行的工单对象 +// - needExecTaskIdToUserId: 需要执行的任务ID到用户ID的映射 +// - isAutoCreated: 可变参数,用于标识工单是否为自动创建 +// * 使用场景: +// - 当工单是通过 AutoCreateAndExecuteWorkflowV1 等自动创建接口创建时,应传递 true +// - 当工单是通过普通创建流程(如 CreateWorkflowV2)创建时,不传递此参数或传递 false +// * 默认行为: +// - 如果不传递此参数(即 len(isAutoCreated) == 0),则默认为 false,使用普通工单的通知类型 +// - 如果传递 true,则使用自动创建工单的特殊通知类型(auto_exec_success/auto_exec_failed) +// - 如果传递 false,则使用普通工单的通知类型(exec_success/exec_failed) +// * 通知类型差异: +// - 自动创建工单: WorkflowNotifyTypeAutoExecuteSuccess/AutoExecuteFail +// - 普通工单: WorkflowNotifyTypeExecuteSuccess/ExecuteFail +// * 注意: 此参数仅影响通知的 action 类型,不影响工单的实际执行逻辑 +func ExecuteWorkflow(workflow *model.Workflow, needExecTaskIdToUserId map[uint]string, isAutoCreated ...bool) (chan string, error) { s := model.GetStorage() l := log.NewEntry() err := s.UpdateStageWorkflowExecTimeIfNeed(workflow.WorkflowId) @@ -150,10 +166,29 @@ func ExecuteWorkflow(workflow *model.Workflow, needExecTaskIdToUserId map[uint]s lock.Unlock() } + // 判断是否为自动创建的工单 + // 逻辑说明: + // - 如果 isAutoCreated 参数未传递(len == 0),则 isAuto = false,使用普通工单通知类型 + // - 如果 isAutoCreated[0] == true,则 isAuto = true,使用自动创建工单的特殊通知类型 + // - 如果 isAutoCreated[0] == false,则 isAuto = false,使用普通工单通知类型 + // 通知类型说明: + // - 自动创建工单成功: WorkflowNotifyTypeAutoExecuteSuccess -> action: "auto_exec_success" + // - 自动创建工单失败: WorkflowNotifyTypeAutoExecuteFail -> action: "auto_exec_failed" + // - 普通工单成功: WorkflowNotifyTypeExecuteSuccess -> action: "exec_success" + // - 普通工单失败: WorkflowNotifyTypeExecuteFail -> action: "exec_failed" + isAuto := len(isAutoCreated) > 0 && isAutoCreated[0] if err != nil || task.Status == model.TaskStatusExecuteFailed { - go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeExecuteFail) + if isAuto { + go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeAutoExecuteFail) + } else { + go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeExecuteFail) + } } else { - go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeExecuteSuccess) + if isAuto { + go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeAutoExecuteSuccess) + } else { + go notification.NotifyWorkflow(string(workflow.ProjectId), workflow.WorkflowId, notification.WorkflowNotifyTypeExecuteSuccess) + } } }() @@ -264,7 +299,19 @@ func RejectWorkflowProcess(workflow *model.Workflow, reason string, user *model. return nil } -func ExecuteTasksProcess(workflowId string, projectUid string, user *model.User) (chan string, error) { +// ExecuteTasksProcess 执行工单任务处理流程 +// 参数说明: +// - workflowId: 工单ID +// - projectUid: 项目UID +// - user: 执行用户 +// - isAutoCreated: 可变参数,用于标识工单是否为自动创建 +// * 使用场景: 与 ExecuteWorkflow 的 isAutoCreated 参数相同 +// * 默认行为: 如果不传递此参数,则默认为 false,表示普通工单 +// * 传递方式: 此参数会透传给 ExecuteWorkflow 函数,用于控制通知类型 +// * 示例: +// - 自动创建工单: ExecuteTasksProcess(workflowId, projectUid, user, true) +// - 普通工单: ExecuteTasksProcess(workflowId, projectUid, user) 或 ExecuteTasksProcess(workflowId, projectUid, user, false) +func ExecuteTasksProcess(workflowId string, projectUid string, user *model.User, isAutoCreated ...bool) (chan string, error) { s := model.GetStorage() workflow, err := dms.GetWorkflowDetailByWorkflowId(projectUid, workflowId, s.GetWorkflowDetailWithoutInstancesByWorkflowID) if err != nil { @@ -280,7 +327,7 @@ func ExecuteTasksProcess(workflowId string, projectUid string, user *model.User) return nil, err } - workflowExecResultChan, err := ExecuteWorkflow(workflow, needExecTaskIds) + workflowExecResultChan, err := ExecuteWorkflow(workflow, needExecTaskIds, isAutoCreated...) if err != nil { return nil, err }