diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AlertType.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AlertType.java
index 058afcb3fc71..6cc850d6f141 100644
--- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AlertType.java
+++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/AlertType.java
@@ -29,7 +29,7 @@ public enum AlertType {
/**
* 0 workflow instance failure, 1 workflow instance success, 2 workflow instance blocked, 3 workflow instance timeout, 4 fault tolerance warning,
- * 5 task failure, 6 task success, 7 task timeout
+ * 5 task failure, 6 task success, 7 task timeout, 8 task result
*/
WORKFLOW_INSTANCE_FAILURE(0, "workflow instance failure"),
WORKFLOW_INSTANCE_SUCCESS(1, "workflow instance success"),
@@ -39,6 +39,7 @@ public enum AlertType {
TASK_FAILURE(5, "task failure"),
TASK_SUCCESS(6, "task success"),
TASK_TIMEOUT(7, "task timeout"),
+ TASK_RESULT(8, "task result"),
;
AlertType(int code, String descp) {
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/AlertDao.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/AlertDao.java
index 19ed2d70f2df..4cc2f2c891a7 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/AlertDao.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/AlertDao.java
@@ -108,6 +108,33 @@ public int addAlert(Alert alert) {
return count;
}
+ /**
+ * Insert a task-result alert idempotently. If an alert with the same sign,
+ * workflow instance id and alert type already exists, the insert is skipped.
+ *
This guards against duplicate inserts caused by at-least-once delivery
+ * of task success lifecycle events.
+ *
+ * @param alert alert, must have sign, workflowInstanceId and alertType set
+ * @return insert count (1 if inserted, 0 if skipped)
+ */
+ public int addTaskResultAlert(Alert alert) {
+ if (null == alert.getAlertGroupId() || NumberUtils.INTEGER_ZERO.equals(alert.getAlertGroupId())) {
+ log.warn("the value of alertGroupId is null or 0 ");
+ return 0;
+ }
+
+ String sign = generateSign(alert);
+ alert.setSign(sign);
+ int count = alertMapper.insertTaskResultAlertIfAbsent(alert);
+ if (count > 0) {
+ log.info("add task result alert to db , alert: {}", alert);
+ } else {
+ log.info("skip duplicate task result alert, sign: {}, workflowInstanceId: {}", sign,
+ alert.getWorkflowInstanceId());
+ }
+ return count;
+ }
+
/**
* update alert sending(execution) status
*
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AlertMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AlertMapper.java
index 0d60891e55f5..dcfdf1ec0e86 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AlertMapper.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/AlertMapper.java
@@ -43,6 +43,12 @@ List listingAlertByStatus(@Param("minAlertId") int minAlertId, @Param("al
void insertAlertWhenServerCrash(@Param("alert") Alert alert,
@Param("crashAlarmSuppressionStartTime") Date crashAlarmSuppressionStartTime);
+ /**
+ * Insert a task-result alert only if no alert with the same sign, workflow instance id and alert type
+ * already exists. This makes the insert idempotent against at-least-once event delivery.
+ */
+ int insertTaskResultAlertIfAbsent(@Param("alert") Alert alert);
+
void deleteByWorkflowInstanceId(@Param("workflowInstanceId") Integer processInstanceId);
List selectByWorkflowInstanceId(@Param("workflowInstanceId") Integer processInstanceId);
diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AlertMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AlertMapper.xml
index 7891dd91376d..df6a3a783556 100644
--- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AlertMapper.xml
+++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/AlertMapper.xml
@@ -51,6 +51,34 @@
having count(*) = 0
+
+
+ insert into t_ds_alert(sign, title, content, alert_status, warning_type, log, alertgroup_id, create_time,
+ update_time, project_code, workflow_definition_code, workflow_instance_id, alert_type)
+ SELECT #{alert.sign},
+ #{alert.title},
+ #{alert.content},
+ #{alert.alertStatus.code},
+ #{alert.warningType.code},
+ #{alert.log},
+ #{alert.alertGroupId},
+ #{alert.createTime},
+ #{alert.updateTime},
+ #{alert.projectCode},
+ #{alert.workflowDefinitionCode},
+ #{alert.workflowInstanceId},
+ #{alert.alertType.code}
+ from t_ds_alert
+ where sign = #{alert.sign}
+ and workflow_instance_id = #{alert.workflowInstanceId}
+ and alert_type = #{alert.alertType.code}
+ having count(*) = 0
+
+