This is an automated email from the ASF dual-hosted git repository.

zihaoxiang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 6221f0211f [Fix-17477] Fix workflow can be deleted which contains 
failover instance (#17478)
6221f0211f is described below

commit 6221f0211f2a0cad32c5fa8276916ce5e78da73b
Author: Wenjun Ruan <[email protected]>
AuthorDate: Tue Sep 16 09:48:23 2025 +0800

    [Fix-17477] Fix workflow can be deleted which contains failover instance 
(#17478)
---
 .../PauseWorkflowInstanceExecutorDelegate.java     |   8 +-
 ...rSuspendedWorkflowInstanceExecutorDelegate.java |   2 +-
 ...eatRunningWorkflowInstanceExecutorDelegate.java |   2 +-
 .../StopWorkflowInstanceExecutorDelegate.java      |   8 +-
 .../api/service/impl/ExecutorServiceImpl.java      |   2 +-
 .../api/service/impl/TaskInstanceServiceImpl.java  |   2 +-
 .../api/service/impl/TenantServiceImpl.java        |   2 +-
 .../api/service/impl/WorkerGroupServiceImpl.java   |   2 +-
 .../impl/WorkflowDefinitionServiceImpl.java        |   4 +-
 .../service/impl/WorkflowInstanceServiceImpl.java  |  10 +-
 .../api/controller/WorkerGroupControllerTest.java  |   2 +-
 .../StopWorkflowInstanceExecuteFunctionTest.java   |  12 +-
 .../api/service/TenantServiceTest.java             |   2 +-
 .../api/service/WorkerGroupServiceTest.java        |   4 +-
 .../common/enums/WorkflowExecutionStatus.java      | 175 ++++++++-------------
 .../common/enums/WorkflowExecutionStatusTest.java  |  93 +++++++++++
 .../dao/repository/impl/TaskInstanceDaoImpl.java   |   2 +-
 .../repository/impl/WorkflowInstanceDaoImpl.java   |   4 +-
 .../dolphinscheduler/dao/utils/WorkflowUtils.java  |   2 +-
 .../impl/WorkflowInstanceDaoImplTest.java          |   7 +-
 .../plugin/subworkflow/SubWorkflowLogicTask.java   |   6 +-
 .../server/master/utils/DependentExecute.java      |   8 +-
 .../cases/WorkflowInstanceFailoverTestCase.java    |  96 +++++------
 ...th_sub_workflow_not_running_in_diff_master.yaml |   2 +-
 .../service/alert/WorkflowAlertManager.java        |   2 +-
 .../service/process/ProcessServiceImpl.java        |   2 +-
 .../service/subworkflow/SubWorkflowService.java    |  44 ------
 .../subworkflow/SubWorkflowServiceImpl.java        | 111 -------------
 28 files changed, 245 insertions(+), 371 deletions(-)

diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/PauseWorkflowInstanceExecutorDelegate.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/PauseWorkflowInstanceExecutorDelegate.java
index 6405596386..0e67388294 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/PauseWorkflowInstanceExecutorDelegate.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/PauseWorkflowInstanceExecutorDelegate.java
@@ -45,7 +45,7 @@ public class PauseWorkflowInstanceExecutorDelegate
     public Void execute(PauseWorkflowInstanceOperation 
workflowInstanceControlRequest) {
         final WorkflowInstance workflowInstance = 
workflowInstanceControlRequest.workflowInstance;
         exceptionIfWorkflowInstanceCannotPause(workflowInstance);
-        if (ifWorkflowInstanceCanDirectPauseInDB(workflowInstance)) {
+        if (workflowInstance.getState().isCanDirectPauseInDB()) {
             directPauseInDB(workflowInstance);
         } else {
             pauseInMaster(workflowInstance);
@@ -55,7 +55,7 @@ public class PauseWorkflowInstanceExecutorDelegate
 
     private void exceptionIfWorkflowInstanceCannotPause(WorkflowInstance 
workflowInstance) {
         WorkflowExecutionStatus workflowInstanceState = 
workflowInstance.getState();
-        if (workflowInstanceState.canPause()) {
+        if (workflowInstanceState.isCanPause()) {
             return;
         }
         throw new ServiceException(
@@ -63,10 +63,6 @@ public class PauseWorkflowInstanceExecutorDelegate
                         + ", can not pause");
     }
 
-    private boolean ifWorkflowInstanceCanDirectPauseInDB(WorkflowInstance 
workflowInstance) {
-        return workflowInstance.getState().canDirectPauseInDB();
-    }
-
     private void directPauseInDB(WorkflowInstance workflowInstance) {
         workflowInstanceDao.updateWorkflowInstanceState(
                 workflowInstance.getId(),
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RecoverSuspendedWorkflowInstanceExecutorDelegate.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RecoverSuspendedWorkflowInstanceExecutorDelegate.java
index 0e107fb9a7..2884d242a9 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RecoverSuspendedWorkflowInstanceExecutorDelegate.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RecoverSuspendedWorkflowInstanceExecutorDelegate.java
@@ -42,7 +42,7 @@ public class RecoverSuspendedWorkflowInstanceExecutorDelegate
     @Override
     public Void execute(RecoverSuspendedWorkflowInstanceOperation 
workflowInstanceControlRequest) {
         final WorkflowInstance workflowInstance = 
workflowInstanceControlRequest.workflowInstance;
-        if (!workflowInstance.getState().isPause() && 
!workflowInstance.getState().isStop()) {
+        if (!workflowInstance.getState().isPaused() && 
!workflowInstance.getState().isStopped()) {
             throw new ServiceException(
                     String.format("The workflow instance: %s state is %s, 
cannot recovery", workflowInstance.getName(),
                             workflowInstance.getState()));
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RepeatRunningWorkflowInstanceExecutorDelegate.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RepeatRunningWorkflowInstanceExecutorDelegate.java
index 8fde42e90d..7aab82b8a2 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RepeatRunningWorkflowInstanceExecutorDelegate.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/RepeatRunningWorkflowInstanceExecutorDelegate.java
@@ -42,7 +42,7 @@ public class RepeatRunningWorkflowInstanceExecutorDelegate
     @Override
     public Void execute(RepeatRunningWorkflowInstanceOperation 
workflowInstanceControlRequest) {
         final WorkflowInstance workflowInstance = 
workflowInstanceControlRequest.workflowInstance;
-        if (workflowInstance.getState() == null || 
!workflowInstance.getState().isFinished()) {
+        if (workflowInstance.getState() == null || 
!workflowInstance.getState().isFinalState()) {
             throw new ServiceException(
                     String.format("The workflow instance: %s status is %s, 
cannot repeat running",
                             workflowInstance.getName(), 
workflowInstance.getState()));
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecutorDelegate.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecutorDelegate.java
index 1d77a3ff45..124c4c6285 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecutorDelegate.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecutorDelegate.java
@@ -46,7 +46,7 @@ public class StopWorkflowInstanceExecutorDelegate
         final WorkflowInstance workflowInstance = 
workflowInstanceControlRequest.workflowInstance;
         exceptionIfWorkflowInstanceCannotStop(workflowInstance);
 
-        if (ifWorkflowInstanceCanDirectStopInDB(workflowInstance)) {
+        if (workflowInstance.getState().isCanDirectStopInDB()) {
             directStopInDB(workflowInstance);
         } else {
             stopInMaster(workflowInstance);
@@ -56,7 +56,7 @@ public class StopWorkflowInstanceExecutorDelegate
 
     void exceptionIfWorkflowInstanceCannotStop(WorkflowInstance 
workflowInstance) {
         final WorkflowExecutionStatus workflowInstanceState = 
workflowInstance.getState();
-        if (workflowInstanceState.canStop()) {
+        if (workflowInstanceState.isCanStop()) {
             return;
         }
         throw new ServiceException(
@@ -64,10 +64,6 @@ public class StopWorkflowInstanceExecutorDelegate
                         + ", can not stop");
     }
 
-    boolean ifWorkflowInstanceCanDirectStopInDB(WorkflowInstance 
workflowInstance) {
-        return workflowInstance.getState().canDirectStopInDB();
-    }
-
     void directStopInDB(WorkflowInstance workflowInstance) {
         workflowInstanceDao.updateWorkflowInstanceState(
                 workflowInstance.getId(),
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
index fac2c57265..c93c237915 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ExecutorServiceImpl.java
@@ -329,7 +329,7 @@ public class ExecutorServiceImpl extends BaseServiceImpl 
implements ExecutorServ
         WorkflowInstance workflowInstance = 
processService.findWorkflowInstanceDetailById(workflowInstanceId)
                 .orElseThrow(() -> new 
ServiceException(Status.WORKFLOW_INSTANCE_NOT_EXIST, workflowInstanceId));
 
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             log.error("Can not execute task for workflow instance which is not 
finished, workflowInstanceId:{}.",
                     workflowInstanceId);
             putMsg(response, Status.WORKFLOW_INSTANCE_IS_NOT_FINISHED);
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskInstanceServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskInstanceServiceImpl.java
index d7f6faea53..1e599eb7a7 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskInstanceServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TaskInstanceServiceImpl.java
@@ -218,7 +218,7 @@ public class TaskInstanceServiceImpl extends 
BaseServiceImpl implements TaskInst
         WorkflowInstance workflowInstance = 
workflowInstanceDao.queryOptionalById(task.getWorkflowInstanceId())
                 .orElseThrow(
                         () -> new 
ServiceException(Status.WORKFLOW_INSTANCE_NOT_EXIST, 
task.getWorkflowInstanceId()));
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             throw new ServiceException("The workflow instance is not finished: 
" + workflowInstance.getState()
                     + " cannot force start task instance");
         }
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TenantServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TenantServiceImpl.java
index d318892a4d..f2dab3b868 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TenantServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/TenantServiceImpl.java
@@ -258,7 +258,7 @@ public class TenantServiceImpl extends BaseServiceImpl 
implements TenantService
     private List<WorkflowInstance> getWorkflowInstancesByTenant(Tenant tenant) 
{
         return workflowInstanceMapper.queryByTenantCodeAndStatus(
                 tenant.getTenantCode(),
-                WorkflowExecutionStatus.getNotTerminalStatus());
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES);
     }
 
     /**
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkerGroupServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkerGroupServiceImpl.java
index eefe307670..331e0ba77a 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkerGroupServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkerGroupServiceImpl.java
@@ -346,7 +346,7 @@ public class WorkerGroupServiceImpl extends BaseServiceImpl 
implements WorkerGro
         }
         List<WorkflowInstance> workflowInstances = 
workflowInstanceMapper.queryByWorkerGroupNameAndStatus(
                 workerGroup.getName(),
-                WorkflowExecutionStatus.getNotTerminalStatus());
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES);
         if (CollectionUtils.isNotEmpty(workflowInstances)) {
             List<Integer> workflowInstanceIds =
                     
workflowInstances.stream().map(WorkflowInstance::getId).collect(Collectors.toList());
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java
index 3a72c7b116..6d9678d06d 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowDefinitionServiceImpl.java
@@ -1054,7 +1054,7 @@ public class WorkflowDefinitionServiceImpl extends 
BaseServiceImpl implements Wo
 
         // check workflow instances is already running
         List<WorkflowInstance> workflowInstances = 
workflowInstanceService.queryByWorkflowDefinitionCodeAndStatus(
-                workflowDefinition.getCode(), 
WorkflowExecutionStatus.getNotTerminalStatus());
+                workflowDefinition.getCode(), 
WorkflowExecutionStatus.NOT_TERMINAL_STATES);
         if (CollectionUtils.isNotEmpty(workflowInstances)) {
             throw new 
ServiceException(Status.DELETE_WORKFLOW_DEFINITION_EXECUTING_FAIL, 
workflowInstances.size());
         }
@@ -2405,7 +2405,7 @@ public class WorkflowDefinitionServiceImpl extends 
BaseServiceImpl implements Wo
         List<WorkflowInstance> workflowInstances = 
workflowInstanceService.queryByWorkflowCodeVersionStatus(
                 code,
                 version,
-                WorkflowExecutionStatus.getNotTerminalStatus());
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES);
         if (CollectionUtils.isNotEmpty(workflowInstances)) {
             throw new 
ServiceException(Status.DELETE_WORKFLOW_DEFINITION_EXECUTING_FAIL, 
workflowInstances.size());
         }
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowInstanceServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowInstanceServiceImpl.java
index cee3d69332..1b3a63fec4 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowInstanceServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/WorkflowInstanceServiceImpl.java
@@ -655,9 +655,9 @@ public class WorkflowInstanceServiceImpl extends 
BaseServiceImpl implements Work
             return result;
         }
         // check workflow instance status
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             log.warn("workflow Instance state is {} so can not update workflow 
instance, workflowInstanceId:{}.",
-                    workflowInstance.getState().getDesc(), workflowInstanceId);
+                    workflowInstance.getState().name(), workflowInstanceId);
             putMsg(result, WORKFLOW_INSTANCE_STATE_OPERATION_ERROR,
                     workflowInstance.getName(), 
workflowInstance.getState().toString(), "update");
             return result;
@@ -835,9 +835,9 @@ public class WorkflowInstanceServiceImpl extends 
BaseServiceImpl implements Work
         projectService.checkProjectAndAuthThrowException(loginUser, project,
                 ApiFuncIdentificationConstant.INSTANCE_DELETE);
         // check workflow instance status
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             log.warn("workflow Instance state is {} so can not delete workflow 
instance, workflowInstanceId:{}.",
-                    workflowInstance.getState().getDesc(), workflowInstanceId);
+                    workflowInstance.getState().name(), workflowInstanceId);
             throw new 
ServiceException(WORKFLOW_INSTANCE_STATE_OPERATION_ERROR, 
workflowInstance.getName(),
                     workflowInstance.getState(), "delete");
         }
@@ -1076,7 +1076,7 @@ public class WorkflowInstanceServiceImpl extends 
BaseServiceImpl implements Work
             }
             log.info("Begin to delete workflow instance, workflow definition 
code: {}", workflowDefinitionCode);
             for (WorkflowInstance workflowInstance : workflowInstances) {
-                if (!workflowInstance.getState().isFinished()) {
+                if (!workflowInstance.getState().isFinalState()) {
                     log.warn("Workflow instance is not finished cannot delete, 
workflow instance id:{}",
                             workflowInstance.getId());
                     throw new 
ServiceException(WORKFLOW_INSTANCE_STATE_OPERATION_ERROR, 
workflowInstance.getName(),
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkerGroupControllerTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkerGroupControllerTest.java
index 06ac58fde5..6153648383 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkerGroupControllerTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/WorkerGroupControllerTest.java
@@ -135,7 +135,7 @@ public class WorkerGroupControllerTest extends 
AbstractControllerTest {
         workerGroup.setName("测试");
         Mockito.when(workerGroupDao.queryById(12)).thenReturn(workerGroup);
         
Mockito.when(workflowInstanceMapper.queryByWorkerGroupNameAndStatus("测试",
-                WorkflowExecutionStatus.getNotTerminalStatus()))
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES))
                 .thenReturn(null);
         Mockito.when(workerGroupDao.deleteById(12)).thenReturn(true);
         
Mockito.when(workflowInstanceMapper.updateWorkflowInstanceByWorkerGroupName("测试",
 "")).thenReturn(1);
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecuteFunctionTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecuteFunctionTest.java
index 60e11477a0..cd982352aa 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecuteFunctionTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/executor/workflow/StopWorkflowInstanceExecuteFunctionTest.java
@@ -96,21 +96,13 @@ class StopWorkflowInstanceExecuteFunctionTest {
     @EnumSource(value = WorkflowExecutionStatus.class, names = {
             "SERIAL_WAIT"})
     void 
ifWorkflowInstanceCanDirectStopInDB_canDirectStopInDB(WorkflowExecutionStatus 
workflowExecutionStatus) {
-        WorkflowInstance workflowInstance = new WorkflowInstance();
-        workflowInstance.setName("Workflow-1");
-        workflowInstance.setState(workflowExecutionStatus);
-        Assertions
-                
.assertTrue(stopWorkflowInstanceExecutorDelegate.ifWorkflowInstanceCanDirectStopInDB(workflowInstance));
+        Assertions.assertTrue(workflowExecutionStatus.isCanDirectStopInDB());
     }
 
     @ParameterizedTest
     @EnumSource(value = WorkflowExecutionStatus.class, names = {
             "SERIAL_WAIT"}, mode = EnumSource.Mode.EXCLUDE)
     void 
ifWorkflowInstanceCanDirectStopInDB_canNotDirectStopInDB(WorkflowExecutionStatus
 workflowExecutionStatus) {
-        WorkflowInstance workflowInstance = new WorkflowInstance();
-        workflowInstance.setName("Workflow-1");
-        workflowInstance.setState(workflowExecutionStatus);
-        Assertions.assertFalse(
-                
stopWorkflowInstanceExecutorDelegate.ifWorkflowInstanceCanDirectStopInDB(workflowInstance));
+        Assertions.assertFalse(workflowExecutionStatus.isCanDirectStopInDB());
     }
 }
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TenantServiceTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TenantServiceTest.java
index c595415b0b..58a36c6348 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TenantServiceTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/TenantServiceTest.java
@@ -192,7 +192,7 @@ public class TenantServiceTest {
                 baseServiceLogger)).thenReturn(true);
         when(tenantMapper.queryById(1)).thenReturn(getTenant());
         when(workflowInstanceMapper.queryByTenantCodeAndStatus(tenantCode,
-                WorkflowExecutionStatus.getNotTerminalStatus()))
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES))
                         .thenReturn(getInstanceList());
         
when(scheduleMapper.queryScheduleListByTenant(tenantCode)).thenReturn(getScheduleList());
         when(userMapper.queryUserListByTenant(3)).thenReturn(getUserList());
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/WorkerGroupServiceTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/WorkerGroupServiceTest.java
index 01a140635e..851cc8ac7b 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/WorkerGroupServiceTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/WorkerGroupServiceTest.java
@@ -237,7 +237,7 @@ public class WorkerGroupServiceTest {
         List<WorkflowInstance> workflowInstances = new 
ArrayList<WorkflowInstance>();
         workflowInstances.add(workflowInstance);
         
when(workflowInstanceMapper.queryByWorkerGroupNameAndStatus(workerGroup.getName(),
-                WorkflowExecutionStatus.getNotTerminalStatus()))
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES))
                         .thenReturn(workflowInstances);
 
         Map<String, Object> deleteFailed = 
workerGroupService.deleteWorkerGroupById(loginUser, 1);
@@ -255,7 +255,7 @@ public class WorkerGroupServiceTest {
         WorkerGroup workerGroup = getWorkerGroup(1);
         when(workerGroupDao.queryById(1)).thenReturn(workerGroup);
         
when(workflowInstanceMapper.queryByWorkerGroupNameAndStatus(workerGroup.getName(),
-                
WorkflowExecutionStatus.getNotTerminalStatus())).thenReturn(null);
+                WorkflowExecutionStatus.NOT_TERMINAL_STATES)).thenReturn(null);
 
         when(workerGroupDao.deleteById(1)).thenReturn(true);
 
diff --git 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatus.java
 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatus.java
index 1cf115b4a2..8c7096060d 100644
--- 
a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatus.java
+++ 
b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatus.java
@@ -17,110 +17,95 @@
 
 package org.apache.dolphinscheduler.common.enums;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Arrays;
 
 import lombok.Getter;
-import lombok.NonNull;
 
 import com.baomidou.mybatisplus.annotation.EnumValue;
 
 @Getter
 public enum WorkflowExecutionStatus {
 
-    SUBMITTED_SUCCESS(0, "submitted"),
-    RUNNING_EXECUTION(1, "running"),
-    READY_PAUSE(2, "ready pause"),
-    PAUSE(3, "pause"),
-    READY_STOP(4, "ready stop"),
-    STOP(5, "stop"),
-    FAILURE(6, "failure"),
-    SUCCESS(7, "success"),
-    SERIAL_WAIT(14, "serial wait"),
-    FAILOVER(18, "failover");
-
-    private static final Map<Integer, WorkflowExecutionStatus> CODE_MAP = new 
HashMap<>();
-    private static final int[] NEED_FAILOVER_STATES = new int[]{
-            RUNNING_EXECUTION.getCode(),
-            READY_PAUSE.getCode(),
-            READY_STOP.getCode()
-    };
-
-    private static final int[] NOT_TERMINAL_STATUS = new int[]{
-            SUBMITTED_SUCCESS.getCode(),
-            RUNNING_EXECUTION.getCode(),
-            READY_PAUSE.getCode(),
-            READY_STOP.getCode(),
-            SERIAL_WAIT.getCode()
-    };
-
-    static {
-        for (WorkflowExecutionStatus executionStatus : 
WorkflowExecutionStatus.values()) {
-            CODE_MAP.put(executionStatus.getCode(), executionStatus);
-        }
-    }
+    SUBMITTED_SUCCESS(0, false, false, false, false, false, false),
+    RUNNING_EXECUTION(1, true, false, true, false, false, true),
+    READY_PAUSE(2, true, false, true, false, false, true),
+    PAUSE(3, false, false, false, false, true, false),
+    READY_STOP(4, true, false, false, false, false, true),
+    STOP(5, false, false, false, false, true, false),
+    FAILURE(6, false, false, false, false, true, false),
+    SUCCESS(7, false, false, false, false, true, false),
+    SERIAL_WAIT(14, true, true, true, true, false, false),
+    FAILOVER(18, false, false, false, false, false, false);
 
     /**
-     * Get <code>WorkflowExecutionStatus</code> by code, if the code is 
invalidated will throw {@link IllegalArgumentException}.
+     * The unique code represent of the state which will be stored in database.
      */
-    public static @NonNull WorkflowExecutionStatus of(int code) {
-        WorkflowExecutionStatus workflowExecutionStatus = CODE_MAP.get(code);
-        if (workflowExecutionStatus == null) {
-            throw new IllegalArgumentException(String.format("The workflow 
execution status code: %s is invalidated",
-                    code));
-        }
-        return workflowExecutionStatus;
-    }
+    @EnumValue
+    private final int code;
 
-    public boolean isRunning() {
-        return this == RUNNING_EXECUTION;
-    }
+    /**
+     * Whether the instance can be stopped, if the state is final state, it 
can't be stopped.
+     * todo: Right now the SUBMITTED_SUCCESS state can't be stopped, we should 
support it in the future.
+     */
+    private final boolean canStop;
 
-    public boolean canStop() {
-        return this == RUNNING_EXECUTION
-                || this == READY_PAUSE
-                || this == READY_STOP
-                || this == SERIAL_WAIT;
-    }
+    /**
+     * Whether the instance can be directly stopped in database, if true, the 
workflow instance will be directly set to STOP state in database.
+     * Right now only serial_wait state support this.
+     * todo: We should support SUBMITTED_SUCCESS state in the future.
+     */
+    private final boolean canDirectStopInDB;
 
-    public boolean canDirectStopInDB() {
-        return this == SERIAL_WAIT;
-    }
+    /**
+     * Whether the instance can be paused, if the state is final state, it 
can't be paused.
+     * todo: Right now the SUBMITTED_SUCCESS state can't be paused, we should 
support it in the future.
+     */
+    private final boolean canPause;
 
-    public boolean canPause() {
-        return this == RUNNING_EXECUTION
-                || this == READY_PAUSE
-                || this == SERIAL_WAIT;
-    }
+    /**
+     * Whether the instance can be directly paused in database, if true, the 
workflow instance will be directly set to PAUSE state in database.
+     * Right now only serial_wait state support this.
+     * todo: We should support SUBMITTED_SUCCESS state in the future.
+     */
+    private final boolean canDirectPauseInDB;
 
     /**
-     * status can be take over on sub-workflow
-     * @return bool
+     * Whether the instance need failover when the instance running on the 
master which is down.
+     * It the instance is launched and not in final state, it should failover.
      */
-    public boolean canTakeover() {
-        return this == RUNNING_EXECUTION
-                || this == READY_PAUSE
-                || this == PAUSE
-                || this == READY_STOP
-                || this == STOP
-                || this == FAILURE
-                || this == SUCCESS
-                || this == FAILOVER;
-    }
+    private final boolean needFailover;
 
-    public boolean canDirectPauseInDB() {
-        return this == SERIAL_WAIT;
+    /**
+     * Whether the state is a final state, if true, means the instance is 
finished and the state will not change unless the user retry/recover it.
+     */
+    private final boolean finalState;
+
+    WorkflowExecutionStatus(int code,
+                            boolean canStop,
+                            boolean canDirectStopInDB,
+                            boolean canPause,
+                            boolean canDirectPauseInDB,
+                            boolean finalState,
+                            boolean needFailover) {
+        this.code = code;
+        this.canStop = canStop;
+        this.canDirectStopInDB = canDirectStopInDB;
+        this.canPause = canPause;
+        this.canDirectPauseInDB = canDirectPauseInDB;
+        this.finalState = finalState;
+        this.needFailover = needFailover;
     }
 
-    public boolean isFinished() {
-        return isSuccess() || isFailure() || isStop() || isPause();
-    }
+    public static final int[] NEED_FAILOVER_STATES = 
Arrays.stream(WorkflowExecutionStatus.values())
+            .filter(WorkflowExecutionStatus::isNeedFailover)
+            .mapToInt(WorkflowExecutionStatus::getCode)
+            .toArray();
+
+    public static final int[] NOT_TERMINAL_STATES = 
Arrays.stream(WorkflowExecutionStatus.values())
+            .filter(workflowExecutionStatus -> 
!workflowExecutionStatus.isFinalState())
+            .mapToInt(WorkflowExecutionStatus::getCode)
+            .toArray();
 
-    /**
-     * status is success
-     *
-     * @return status
-     */
     public boolean isSuccess() {
         return this == SUCCESS;
     }
@@ -129,36 +114,14 @@ public enum WorkflowExecutionStatus {
         return this == FAILURE;
     }
 
-    public boolean isPause() {
+    public boolean isPaused() {
         return this == PAUSE;
     }
 
-    public boolean isReadyStop() {
-        return this == READY_STOP;
-    }
-
-    public boolean isStop() {
+    public boolean isStopped() {
         return this == STOP;
     }
 
-    public static int[] getNeedFailoverWorkflowInstanceState() {
-        return NEED_FAILOVER_STATES;
-    }
-
-    public static int[] getNotTerminalStatus() {
-        return NOT_TERMINAL_STATUS;
-    }
-
-    @EnumValue
-    private final int code;
-
-    private final String desc;
-
-    WorkflowExecutionStatus(int code, String desc) {
-        this.code = code;
-        this.desc = desc;
-    }
-
     @Override
     public String toString() {
         return name();
diff --git 
a/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatusTest.java
 
b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatusTest.java
new file mode 100644
index 0000000000..7fdf81e363
--- /dev/null
+++ 
b/dolphinscheduler-common/src/test/java/org/apache/dolphinscheduler/common/enums/WorkflowExecutionStatusTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.common.enums;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class WorkflowExecutionStatusTest {
+
+    @Test
+    void testIsSuccess() {
+        assertThat(WorkflowExecutionStatus.SUCCESS.isSuccess()).isTrue();
+    }
+
+    @Test
+    void testIsFailure() {
+        assertThat(WorkflowExecutionStatus.FAILURE.isFailure()).isTrue();
+    }
+
+    @Test
+    void testIsPaused() {
+        assertThat(WorkflowExecutionStatus.PAUSE.isPaused()).isTrue();
+    }
+
+    @Test
+    void testIsStopped() {
+        assertThat(WorkflowExecutionStatus.STOP.isStopped()).isTrue();
+    }
+
+    @Test
+    void testNonTerminalStates() {
+        
assertThat(WorkflowExecutionStatus.NOT_TERMINAL_STATES).asList().containsExactly(
+                WorkflowExecutionStatus.SUBMITTED_SUCCESS.getCode(),
+                WorkflowExecutionStatus.RUNNING_EXECUTION.getCode(),
+                WorkflowExecutionStatus.READY_PAUSE.getCode(),
+                WorkflowExecutionStatus.READY_STOP.getCode(),
+                WorkflowExecutionStatus.SERIAL_WAIT.getCode(),
+                WorkflowExecutionStatus.FAILOVER.getCode());
+    }
+
+    @Test
+    void testNeedFailoverStates() {
+        
assertThat(WorkflowExecutionStatus.NEED_FAILOVER_STATES).asList().containsExactly(
+                WorkflowExecutionStatus.RUNNING_EXECUTION.getCode(),
+                WorkflowExecutionStatus.READY_PAUSE.getCode(),
+                WorkflowExecutionStatus.READY_STOP.getCode());
+    }
+
+    @Test
+    void testCanStop() {
+        
assertThat(WorkflowExecutionStatus.SUBMITTED_SUCCESS.isCanStop()).isFalse();
+        
assertThat(WorkflowExecutionStatus.RUNNING_EXECUTION.isCanStop()).isTrue();
+        assertThat(WorkflowExecutionStatus.READY_PAUSE.isCanStop()).isTrue();
+        assertThat(WorkflowExecutionStatus.PAUSE.isCanStop()).isFalse();
+        assertThat(WorkflowExecutionStatus.READY_STOP.isCanStop()).isTrue();
+        assertThat(WorkflowExecutionStatus.STOP.isCanStop()).isFalse();
+        assertThat(WorkflowExecutionStatus.FAILURE.isCanStop()).isFalse();
+        assertThat(WorkflowExecutionStatus.SUCCESS.isCanStop()).isFalse();
+        assertThat(WorkflowExecutionStatus.SERIAL_WAIT.isCanStop()).isTrue();
+        assertThat(WorkflowExecutionStatus.FAILOVER.isCanStop()).isFalse();
+    }
+
+    @Test
+    void testCanPause() {
+        
assertThat(WorkflowExecutionStatus.SUBMITTED_SUCCESS.isCanPause()).isFalse();
+        
assertThat(WorkflowExecutionStatus.RUNNING_EXECUTION.isCanPause()).isTrue();
+        assertThat(WorkflowExecutionStatus.READY_PAUSE.isCanPause()).isTrue();
+        assertThat(WorkflowExecutionStatus.PAUSE.isCanPause()).isFalse();
+        assertThat(WorkflowExecutionStatus.READY_STOP.isCanPause()).isFalse();
+        assertThat(WorkflowExecutionStatus.STOP.isCanPause()).isFalse();
+        assertThat(WorkflowExecutionStatus.FAILURE.isCanPause()).isFalse();
+        assertThat(WorkflowExecutionStatus.SUCCESS.isCanPause()).isFalse();
+        assertThat(WorkflowExecutionStatus.SERIAL_WAIT.isCanPause()).isTrue();
+        assertThat(WorkflowExecutionStatus.FAILOVER.isCanPause()).isFalse();
+    }
+
+}
diff --git 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TaskInstanceDaoImpl.java
 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TaskInstanceDaoImpl.java
index 1bed138bda..c675f502aa 100644
--- 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TaskInstanceDaoImpl.java
+++ 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/TaskInstanceDaoImpl.java
@@ -66,7 +66,7 @@ public class TaskInstanceDaoImpl extends 
BaseDao<TaskInstance, TaskInstanceMappe
     @Override
     public boolean submitTaskInstanceToDB(TaskInstance taskInstance, 
WorkflowInstance workflowInstance) {
         WorkflowExecutionStatus processInstanceState = 
workflowInstance.getState();
-        if (processInstanceState.isFinished() || processInstanceState == 
WorkflowExecutionStatus.READY_STOP) {
+        if (processInstanceState.isFinalState() || processInstanceState == 
WorkflowExecutionStatus.READY_STOP) {
             log.warn("processInstance: {} state was: {}, skip submit this 
task, taskCode: {}",
                     workflowInstance.getId(),
                     processInstanceState,
diff --git 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImpl.java
 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImpl.java
index cfc381ab8a..7e58b8495c 100644
--- 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImpl.java
+++ 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImpl.java
@@ -171,12 +171,12 @@ public class WorkflowInstanceDaoImpl extends 
BaseDao<WorkflowInstance, WorkflowI
     @Override
     public List<String> queryNeedFailoverMasters() {
         return mybatisMapper
-                
.queryNeedFailoverWorkflowInstanceHost(WorkflowExecutionStatus.getNeedFailoverWorkflowInstanceState());
+                
.queryNeedFailoverWorkflowInstanceHost(WorkflowExecutionStatus.NEED_FAILOVER_STATES);
     }
 
     @Override
     public List<WorkflowInstance> queryNeedFailoverWorkflowInstances(String 
masterAddress) {
         return mybatisMapper.queryByHostAndStatus(masterAddress,
-                
WorkflowExecutionStatus.getNeedFailoverWorkflowInstanceState());
+                WorkflowExecutionStatus.NEED_FAILOVER_STATES);
     }
 }
diff --git 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/utils/WorkflowUtils.java
 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/utils/WorkflowUtils.java
index 839ffc7dc9..ad07d9e023 100644
--- 
a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/utils/WorkflowUtils.java
+++ 
b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/utils/WorkflowUtils.java
@@ -35,7 +35,7 @@ public class WorkflowUtils {
      * @return workflow duration
      */
     public static String getWorkflowInstanceDuration(WorkflowInstance 
workflowInstance) {
-        return workflowInstance.getState() != null && 
workflowInstance.getState().isFinished()
+        return workflowInstance.getState() != null && 
workflowInstance.getState().isFinalState()
                 ? DateUtils.format2Duration(workflowInstance.getStartTime(), 
workflowInstance.getEndTime())
                 : DateUtils.format2Duration(workflowInstance.getStartTime(), 
new Date());
     }
diff --git 
a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImplTest.java
 
b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImplTest.java
index 520a9b907e..1860b0d389 100644
--- 
a/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImplTest.java
+++ 
b/dolphinscheduler-dao/src/test/java/org/apache/dolphinscheduler/dao/repository/impl/WorkflowInstanceDaoImplTest.java
@@ -41,17 +41,16 @@ class WorkflowInstanceDaoImplTest extends BaseDaoTest {
     void queryByWorkflowCodeVersionStatus_EMPTY_INSTANCE() {
         long workflowDefinitionCode = 1L;
         int workflowDefinitionVersion = 1;
-        int[] status = 
WorkflowExecutionStatus.getNeedFailoverWorkflowInstanceState();
 
         
assertTrue(isEmpty(workflowInstanceDao.queryByWorkflowCodeVersionStatus(workflowDefinitionCode,
-                workflowDefinitionVersion, status)));
+                workflowDefinitionVersion, 
WorkflowExecutionStatus.NEED_FAILOVER_STATES)));
     }
 
     @Test
     void queryByWorkflowCodeVersionStatus_EXIST_NOT_FINISH_INSTANCE() {
         long workflowDefinitionCode = 1L;
         int workflowDefinitionVersion = 1;
-        int[] status = WorkflowExecutionStatus.getNotTerminalStatus();
+        int[] status = WorkflowExecutionStatus.NOT_TERMINAL_STATES;
 
         
assertTrue(isEmpty(workflowInstanceDao.queryByWorkflowCodeVersionStatus(workflowDefinitionCode,
                 workflowDefinitionVersion, status)));
@@ -101,7 +100,7 @@ class WorkflowInstanceDaoImplTest extends BaseDaoTest {
     void queryByWorkflowCodeVersionStatus_EXIST_FINISH_INSTANCE() {
         long workflowDefinitionCode = 1L;
         int workflowDefinitionVersion = 1;
-        int[] status = WorkflowExecutionStatus.getNotTerminalStatus();
+        int[] status = WorkflowExecutionStatus.NOT_TERMINAL_STATES;
 
         
workflowInstanceDao.insert(createWorkflowInstance(workflowDefinitionCode, 
workflowDefinitionVersion,
                 WorkflowExecutionStatus.PAUSE));
diff --git 
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/subworkflow/SubWorkflowLogicTask.java
 
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/subworkflow/SubWorkflowLogicTask.java
index 82c435583f..89222ebc24 100644
--- 
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/subworkflow/SubWorkflowLogicTask.java
+++ 
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/subworkflow/SubWorkflowLogicTask.java
@@ -167,9 +167,9 @@ public class SubWorkflowLogicTask extends 
AbstractLogicTask<SubWorkflowParameter
         final WorkflowInstance subWorkflowInstance = 
workflowInstanceDao.queryById(
                 subWorkflowLogicTaskRuntimeContext.getSubWorkflowInstanceId());
 
-        if (subWorkflowInstance != null && 
subWorkflowInstance.getState().canTakeover()) {
-            // Here we only need to take over the runtime context of 
sub-workflow,
-            // the sub-workflow will be failover by master-server when needed.
+        if (subWorkflowInstance != null) {
+            // If the sub workflow instance is existed, means we already 
trigger the sub workflow instance.
+            // So we don't need to trigger again.
             return subWorkflowLogicTaskRuntimeContext;
         }
 
diff --git 
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/utils/DependentExecute.java
 
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/utils/DependentExecute.java
index a66ed1bb33..e6e4d16ff1 100644
--- 
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/utils/DependentExecute.java
+++ 
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/utils/DependentExecute.java
@@ -180,7 +180,7 @@ public class DependentExecute {
      * @return
      */
     private DependResult dependResultByWorkflowInstance(WorkflowInstance 
workflowInstance) {
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             return DependResult.WAITING;
         }
         if (workflowInstance.getState().isSuccess()) {
@@ -199,7 +199,7 @@ public class DependentExecute {
      * @return
      */
     private DependResult 
dependResultByAllTaskOfWorkflowInstance(WorkflowInstance workflowInstance) {
-        if (!workflowInstance.getState().isFinished()) {
+        if (!workflowInstance.getState().isFinalState()) {
             log.info(
                     "Wait for the dependent workflow to complete, 
workflowDefinitionCode: {}, pworkflowInstanceId: {}.",
                     workflowInstance.getWorkflowDefinitionCode(), 
workflowInstance.getId());
@@ -272,7 +272,7 @@ public class DependentExecute {
                 return DependResult.SUCCESS;
             }
 
-            if (!workflowInstance.getState().isFinished()) {
+            if (!workflowInstance.getState().isFinalState()) {
                 log.info(
                         "Wait for the dependent workflow to complete, 
workflowDefinitionCode: {}, workflowInstanceId: {}.",
                         workflowInstance.getWorkflowDefinitionCode(), 
workflowInstance.getId());
@@ -362,7 +362,7 @@ public class DependentExecute {
         } else if (state.isSuccess()) {
             return DependResult.SUCCESS;
         } else {
-            if (workflowInstance.getState().isRunning()
+            if (!workflowInstance.getState().isFinalState()
                     && taskInstance.getRetryTimes() < 
taskInstance.getMaxRetryTimes()) {
                 log.info("taskDefinitionCode: {}, taskDefinitionName: {}, 
retryTimes: {}, maxRetryTimes: {}",
                         taskInstance.getTaskCode(), taskInstance.getName(), 
taskInstance.getRetryTimes(),
diff --git 
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceFailoverTestCase.java
 
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceFailoverTestCase.java
index ab6f751df4..1be7f71f7f 100644
--- 
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceFailoverTestCase.java
+++ 
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceFailoverTestCase.java
@@ -37,7 +37,6 @@ import 
org.apache.dolphinscheduler.server.master.cluster.MasterServerMetadata;
 import org.apache.dolphinscheduler.server.master.engine.system.SystemEventBus;
 import 
org.apache.dolphinscheduler.server.master.engine.system.event.GlobalMasterFailoverEvent;
 import 
org.apache.dolphinscheduler.server.master.engine.system.event.MasterFailoverEvent;
-import org.apache.dolphinscheduler.server.master.failover.FailoverCoordinator;
 import 
org.apache.dolphinscheduler.server.master.integration.WorkflowTestCaseContext;
 
 import org.apache.commons.lang3.StringUtils;
@@ -45,6 +44,7 @@ import org.apache.commons.lang3.StringUtils;
 import java.time.Duration;
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -54,9 +54,6 @@ public class WorkflowInstanceFailoverTestCase extends 
AbstractMasterIntegrationT
     @Autowired
     private SystemEventBus systemEventBus;
 
-    @Autowired
-    FailoverCoordinator failoverCoordinator;
-
     @Test
     public void testGlobalFailover_runningWorkflow_withSubmittedTasks() {
         final String yaml = 
"/it/failover/running_workflowInstance_with_one_submitted_fake_task.yaml";
@@ -895,69 +892,62 @@ public class WorkflowInstanceFailoverTestCase extends 
AbstractMasterIntegrationT
         assertThat(mainWorkflowInstance).isNotNull();
         assertThat(submittedSubWorkflowInstance).isNotNull();
 
-        MasterServerMetadata masterServerMain = MasterServerMetadata.builder()
-                .cpuUsage(0.2)
-                .memoryUsage(0.4)
-                .serverStatus(ServerStatus.NORMAL)
-                .address(mainWorkflowInstance.getHost())
-                .build();
-        MasterServerMetadata masterServerSub = MasterServerMetadata.builder()
-                .cpuUsage(0.2)
-                .memoryUsage(0.4)
-                .serverStatus(ServerStatus.NORMAL)
-                .address(submittedSubWorkflowInstance.getHost())
-                .build();
-
-        // first start workflow to simulate the normal parent workflow
-        systemEventBus.publish(MasterFailoverEvent.of(masterServerMain, new 
Date(), 0));
-
-        final String mainMasterFailoverNodePath = 
RegistryUtils.getFailoveredNodePath(
-                masterServerMain.getAddress(),
-                masterServerMain.getServerStartupTime(),
-                masterServerMain.getProcessId());
-        // wait failover main-workflow
+        // Failover the main and sub workflow master
+        systemEventBus.publish(GlobalMasterFailoverEvent.of(new Date()));
+        // wait failover finished
         await()
                 .atMost(Duration.ofMinutes(1))
                 .pollInterval(Duration.ofMillis(500))
                 .untilAsserted(() -> {
-                    
assertThat(registryClient.exists(mainMasterFailoverNodePath)).isTrue();
+                    assertThat(registryClient
+                            
.exists(RegistryUtils.getGlobalMasterFailoverNodePath(mainWorkflowInstance.getHost())))
+                                    .isTrue();
+                    assertThat(registryClient.exists(
+                            
RegistryUtils.getGlobalMasterFailoverNodePath(submittedSubWorkflowInstance.getHost())))
+                                    .isTrue();
                 });
 
-        await()
-                .atMost(Duration.ofMinutes(1))
-                .pollInterval(Duration.ofMillis(500))
-                .untilAsserted(() -> {
-                    assertThat(repository.queryWorkflowInstance(1).getState())
-                            .isEqualTo(WorkflowExecutionStatus.SUCCESS);
-                });
+        // Two workflow instance is success
         await()
                 .atMost(Duration.ofMinutes(1))
                 .pollInterval(Duration.ofMillis(500))
                 .untilAsserted(() -> {
                     assertThat(repository.queryAllWorkflowInstance())
-                            .hasSize(3)
-                            .filteredOn(workflowInstance -> 
workflowInstance.getId() == 3)
-                            .allSatisfy(workflowInstance -> {
-                                assertThat(workflowInstance.getState())
-                                        
.isEqualTo(WorkflowExecutionStatus.SUCCESS);
-                            });
-                });
-
-        await()
-                .atMost(Duration.ofMinutes(1))
-                .pollInterval(Duration.ofMillis(500))
-                .untilAsserted(() -> {
-                    assertThat(repository.queryAllTaskInstance())
-                            .hasSize(3)
-                            .filteredOn(taskInstance -> taskInstance.getId() > 
1)
-                            .allSatisfy(taskInstance -> {
-                                assertThat(taskInstance.getState())
-                                        
.isEqualTo(TaskExecutionStatus.SUCCESS);
+                            .hasSize(2)
+                            .satisfies(workflowInstances -> {
+                                // Main workflow instance should be success
+                                // And the sub-workflow task instance should 
be success too.
+                                assertThat(workflowInstances)
+                                        .filteredOn(workflowInstance -> 
Objects.equals(workflowInstance.getId(),
+                                                mainWorkflowInstance.getId()))
+                                        .satisfiesExactly(workflowInstance -> 
assertThat(workflowInstance.getState())
+                                                
.isEqualTo(WorkflowExecutionStatus.SUCCESS))
+                                        .satisfiesExactly(workflowInstance -> {
+                                            
assertThat(repository.queryTaskInstance(mainWorkflowInstance.getId()))
+                                                    .hasSize(2)
+                                                    .anySatisfy(taskInstance 
-> assertThat(taskInstance.getState())
+                                                            
.isEqualTo(TaskExecutionStatus.NEED_FAULT_TOLERANCE))
+                                                    .anySatisfy(taskInstance 
-> assertThat(taskInstance.getState())
+                                                            
.isEqualTo(TaskExecutionStatus.SUCCESS));
+                                        });
+                                // Sub-workflow instance should be success.
+                                // The task instance in sub-workflow should be 
failover.
+                                assertThat(workflowInstances)
+                                        .filteredOn(workflowInstance -> 
Objects.equals(workflowInstance.getId(),
+                                                
submittedSubWorkflowInstance.getId()))
+                                        .satisfiesExactly(workflowInstance -> 
assertThat(workflowInstance.getState())
+                                                
.isEqualTo(WorkflowExecutionStatus.SUCCESS))
+                                        .satisfiesExactly(workflowInstance -> {
+                                            assertThat(
+                                                    
repository.queryTaskInstance(submittedSubWorkflowInstance.getId()))
+                                                            .hasSize(1)
+                                                            .satisfiesExactly(
+                                                                    
taskInstance -> assertThat(taskInstance.getState())
+                                                                            
.isEqualTo(TaskExecutionStatus.SUCCESS));
+                                        });
                             });
                 });
-
         masterContainer.assertAllResourceReleased();
-
     }
 
     @Test
diff --git 
a/dolphinscheduler-master/src/test/resources/it/failover/running_workflowInstance_with_sub_workflow_not_running_in_diff_master.yaml
 
b/dolphinscheduler-master/src/test/resources/it/failover/running_workflowInstance_with_sub_workflow_not_running_in_diff_master.yaml
index a97c4f4e45..c519312248 100644
--- 
a/dolphinscheduler-master/src/test/resources/it/failover/running_workflowInstance_with_sub_workflow_not_running_in_diff_master.yaml
+++ 
b/dolphinscheduler-master/src/test/resources/it/failover/running_workflowInstance_with_sub_workflow_not_running_in_diff_master.yaml
@@ -101,7 +101,7 @@ workflowInstances:
     workflowDefinitionCode: 2
     workflowDefinitionVersion: 1
     projectCode: 1
-    state: SUBMITTED_SUCCESS
+    state: RUNNING_EXECUTION
     recovery: NO
     startTime: 2025-04-24 18:00:00
     endTime: null
diff --git 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/alert/WorkflowAlertManager.java
 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/alert/WorkflowAlertManager.java
index ede66d3eaa..b792ee5089 100644
--- 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/alert/WorkflowAlertManager.java
+++ 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/alert/WorkflowAlertManager.java
@@ -240,7 +240,7 @@ public class WorkflowAlertManager {
         WarningType warningType = workflowInstance.getWarningType();
         switch (warningType) {
             case ALL:
-                if (workflowInstance.getState().isFinished()) {
+                if (workflowInstance.getState().isFinalState()) {
                     sendWarning = true;
                 }
                 break;
diff --git 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/process/ProcessServiceImpl.java
 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/process/ProcessServiceImpl.java
index bf6805afa4..fb9b66b936 100644
--- 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/process/ProcessServiceImpl.java
+++ 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/process/ProcessServiceImpl.java
@@ -754,7 +754,7 @@ public class ProcessServiceImpl implements ProcessService {
     public void forceWorkflowInstanceSuccessByTaskInstanceId(TaskInstance 
task) {
         WorkflowInstance workflowInstance = 
findWorkflowInstanceDetailById(task.getWorkflowInstanceId()).orElse(null);
         if (workflowInstance != null
-                && (workflowInstance.getState().isFailure() || 
workflowInstance.getState().isStop())) {
+                && (workflowInstance.getState().isFailure() || 
workflowInstance.getState().isStopped())) {
             List<TaskInstance> validTaskList =
                     
taskInstanceDao.queryValidTaskListByWorkflowInstanceId(workflowInstance.getId());
             List<Long> instanceTaskCodeList =
diff --git 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowService.java
 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowService.java
deleted file mode 100644
index ae50ddaa2a..0000000000
--- 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowService.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.dolphinscheduler.service.subworkflow;
-
-import org.apache.dolphinscheduler.dao.entity.RelationSubWorkflow;
-import org.apache.dolphinscheduler.dao.entity.WorkflowInstance;
-import org.apache.dolphinscheduler.plugin.task.api.model.Property;
-
-import java.util.List;
-
-import org.springframework.stereotype.Component;
-
-@Component
-public interface SubWorkflowService {
-
-    List<WorkflowInstance> getAllDynamicSubWorkflow(long processInstanceId, 
long taskCode);
-
-    int batchInsertRelationSubWorkflow(List<RelationSubWorkflow> 
relationSubWorkflowList);
-
-    List<WorkflowInstance> filterFinishProcessInstances(List<WorkflowInstance> 
workflowInstanceList);
-
-    List<WorkflowInstance> 
filterSuccessProcessInstances(List<WorkflowInstance> workflowInstanceList);
-
-    List<WorkflowInstance> 
filterRunningProcessInstances(List<WorkflowInstance> workflowInstanceList);
-
-    List<WorkflowInstance> filterFailedProcessInstances(List<WorkflowInstance> 
workflowInstanceList);
-
-    List<Property> getWorkflowOutputParameters(WorkflowInstance 
workflowInstance);
-}
diff --git 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowServiceImpl.java
 
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowServiceImpl.java
deleted file mode 100644
index cbdc996722..0000000000
--- 
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/subworkflow/SubWorkflowServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.dolphinscheduler.service.subworkflow;
-
-import org.apache.dolphinscheduler.common.utils.JSONUtils;
-import org.apache.dolphinscheduler.dao.entity.RelationSubWorkflow;
-import org.apache.dolphinscheduler.dao.entity.WorkflowDefinitionLog;
-import org.apache.dolphinscheduler.dao.entity.WorkflowInstance;
-import org.apache.dolphinscheduler.dao.mapper.RelationSubWorkflowMapper;
-import org.apache.dolphinscheduler.dao.mapper.WorkflowDefinitionLogMapper;
-import org.apache.dolphinscheduler.dao.repository.WorkflowInstanceDao;
-import org.apache.dolphinscheduler.plugin.task.api.model.Property;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-@Component
-public class SubWorkflowServiceImpl implements SubWorkflowService {
-
-    @Autowired
-    private RelationSubWorkflowMapper relationSubWorkflowMapper;
-
-    @Autowired
-    private WorkflowInstanceDao workflowInstanceDao;
-
-    @Autowired
-    private WorkflowDefinitionLogMapper workflowDefinitionLogMapper;
-
-    @Override
-    public List<WorkflowInstance> getAllDynamicSubWorkflow(long 
processInstanceId, long taskCode) {
-        List<RelationSubWorkflow> relationSubWorkflows =
-                
relationSubWorkflowMapper.queryAllSubWorkflowInstance(processInstanceId, 
taskCode);
-        List<Long> allSubProcessInstanceId = relationSubWorkflows.stream()
-                
.map(RelationSubWorkflow::getSubWorkflowInstanceId).collect(Collectors.toList());
-
-        List<WorkflowInstance> allSubWorkflowInstance = 
workflowInstanceDao.queryByIds(allSubProcessInstanceId);
-        
allSubWorkflowInstance.sort(Comparator.comparing(WorkflowInstance::getId));
-        return allSubWorkflowInstance;
-    }
-
-    @Override
-    public int batchInsertRelationSubWorkflow(List<RelationSubWorkflow> 
relationSubWorkflowList) {
-        int insertN = 
relationSubWorkflowMapper.batchInsert(relationSubWorkflowList);
-        return insertN;
-    }
-
-    @Override
-    public List<WorkflowInstance> 
filterFinishProcessInstances(List<WorkflowInstance> workflowInstanceList) {
-        return workflowInstanceList.stream()
-                .filter(subProcessInstance -> 
subProcessInstance.getState().isFinished()).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<WorkflowInstance> 
filterSuccessProcessInstances(List<WorkflowInstance> workflowInstanceList) {
-        return workflowInstanceList.stream()
-                .filter(subProcessInstance -> 
subProcessInstance.getState().isSuccess()).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<WorkflowInstance> 
filterRunningProcessInstances(List<WorkflowInstance> workflowInstanceList) {
-        return workflowInstanceList.stream()
-                .filter(subProcessInstance -> 
subProcessInstance.getState().isRunning()).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<WorkflowInstance> 
filterFailedProcessInstances(List<WorkflowInstance> workflowInstanceList) {
-        return workflowInstanceList.stream()
-                .filter(subProcessInstance -> 
subProcessInstance.getState().isFailure()).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<Property> getWorkflowOutputParameters(WorkflowInstance 
workflowInstance) {
-        List<Property> outputParamList =
-                new 
ArrayList<>(JSONUtils.toList(workflowInstance.getVarPool(), Property.class));
-
-        WorkflowDefinitionLog processDefinition = workflowDefinitionLogMapper
-                
.queryByDefinitionCodeAndVersion(workflowInstance.getWorkflowDefinitionCode(),
-                        workflowInstance.getWorkflowDefinitionVersion());
-        List<Property> globalParamList = 
JSONUtils.toList(processDefinition.getGlobalParams(), Property.class);
-
-        Set<String> ouputParamSet = 
outputParamList.stream().map(Property::getProp).collect(Collectors.toSet());
-
-        // add output global parameters which are not in output parameters list
-        globalParamList.stream().filter(globalParam -> 
!ouputParamSet.contains(globalParam.getProp()))
-                .forEach(outputParamList::add);
-
-        return outputParamList;
-
-    }
-}

Reply via email to