This is an automated email from the ASF dual-hosted git repository.
wenjun 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 5a93624ace [Fix-17354][Master] Killed state of timeout failure
strategy will cause workflow can't finish or stop (#17392)
5a93624ace is described below
commit 5a93624aceda7fde573908b41cf28c30f9f98acd
Author: Wenjun Ruan <[email protected]>
AuthorDate: Tue Aug 5 20:01:06 2025 +0800
[Fix-17354][Master] Killed state of timeout failure strategy will cause
workflow can't finish or stop (#17392)
---
.../engine/graph/IWorkflowExecutionGraph.java | 4 +-
.../engine/graph/WorkflowExecutionGraph.java | 8 +-
.../WorkflowReadyPauseStateAction.java | 8 +-
.../statemachine/WorkflowReadyStopStateAction.java | 2 +-
.../statemachine/WorkflowRunningStateAction.java | 20 ++++-
.../integration/WorkflowTestCaseContext.java | 10 +++
.../integration/cases/WorkflowStartTestCase.java | 31 +++++++
.../it/start/workflow_with_timeout_kill_task.yaml | 95 ++++++++++++++++++++++
8 files changed, 165 insertions(+), 13 deletions(-)
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/IWorkflowExecutionGraph.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/IWorkflowExecutionGraph.java
index d9266b721c..fdbbb581da 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/IWorkflowExecutionGraph.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/IWorkflowExecutionGraph.java
@@ -182,12 +182,12 @@ public interface IWorkflowExecutionGraph {
/**
* Whether there exist the TaskExecutionRunnable chain in the graph is
finish with paused.
*/
- boolean isExistPauseTaskExecutionRunnableChain();
+ boolean isExistPausedTaskExecutionRunnableChain();
/**
* Whether there exist the TaskExecutionRunnable chain in the graph is
finish with kill.
*/
- boolean isExistKillTaskExecutionRunnableChain();
+ boolean isExistKilledTaskExecutionRunnableChain();
/**
* Check whether the given task is the end of the task chain.
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/WorkflowExecutionGraph.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/WorkflowExecutionGraph.java
index a9ce38cc7b..0fa4d15cac 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/WorkflowExecutionGraph.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/graph/WorkflowExecutionGraph.java
@@ -204,8 +204,8 @@ public class WorkflowExecutionGraph implements
IWorkflowExecutionGraph {
return false;
}
return !isExistFailureTaskExecutionRunnableChain()
- && !isExistPauseTaskExecutionRunnableChain()
- && !isExistKillTaskExecutionRunnableChain();
+ && !isExistPausedTaskExecutionRunnableChain()
+ && !isExistKilledTaskExecutionRunnableChain();
}
@Override
@@ -214,12 +214,12 @@ public class WorkflowExecutionGraph implements
IWorkflowExecutionGraph {
}
@Override
- public boolean isExistPauseTaskExecutionRunnableChain() {
+ public boolean isExistPausedTaskExecutionRunnableChain() {
return CollectionUtils.isNotEmpty(pausedTaskChains);
}
@Override
- public boolean isExistKillTaskExecutionRunnableChain() {
+ public boolean isExistKilledTaskExecutionRunnableChain() {
return CollectionUtils.isNotEmpty(killedTaskChains);
}
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyPauseStateAction.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyPauseStateAction.java
index 9f002d1acb..8d677a3190 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyPauseStateAction.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyPauseStateAction.java
@@ -120,13 +120,13 @@ public class WorkflowReadyPauseStateAction extends
AbstractWorkflowStateAction {
}
final WorkflowEventBus workflowEventBus =
workflowExecutionRunnable.getWorkflowEventBus();
- if (workflowExecutionGraph.isExistFailureTaskExecutionRunnableChain())
{
-
workflowEventBus.publish(WorkflowFailedLifecycleEvent.of(workflowExecutionRunnable));
+ if (workflowExecutionGraph.isExistPausedTaskExecutionRunnableChain()) {
+
workflowEventBus.publish(WorkflowPausedLifecycleEvent.of(workflowExecutionRunnable));
return;
}
- if (workflowExecutionGraph.isExistPauseTaskExecutionRunnableChain()) {
-
workflowEventBus.publish(WorkflowPausedLifecycleEvent.of(workflowExecutionRunnable));
+ if (workflowExecutionGraph.isExistFailureTaskExecutionRunnableChain())
{
+
workflowEventBus.publish(WorkflowFailedLifecycleEvent.of(workflowExecutionRunnable));
return;
}
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyStopStateAction.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyStopStateAction.java
index 7f40a4d714..b651d2223d 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyStopStateAction.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowReadyStopStateAction.java
@@ -120,7 +120,7 @@ public class WorkflowReadyStopStateAction extends
AbstractWorkflowStateAction {
}
final WorkflowEventBus workflowEventBus =
workflowExecutionRunnable.getWorkflowEventBus();
- if (workflowExecutionGraph.isExistKillTaskExecutionRunnableChain()) {
+ if (workflowExecutionGraph.isExistKilledTaskExecutionRunnableChain()) {
workflowEventBus.publish(WorkflowStoppedLifecycleEvent.of(workflowExecutionRunnable));
return;
}
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowRunningStateAction.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowRunningStateAction.java
index 934a727afe..469736cea5 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowRunningStateAction.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/WorkflowRunningStateAction.java
@@ -84,7 +84,13 @@ public class WorkflowRunningStateAction extends
AbstractWorkflowStateAction {
public void onStoppedEvent(final IWorkflowExecutionRunnable
workflowExecutionRunnable,
final WorkflowStoppedLifecycleEvent
workflowStoppedEvent) {
throwExceptionIfStateIsNotMatch(workflowExecutionRunnable);
- logWarningIfCannotDoAction(workflowExecutionRunnable,
workflowStoppedEvent);
+ // [Fix-17354]
+ if
(!workflowExecutionRunnable.getWorkflowExecutionGraph().isExistKilledTaskExecutionRunnableChain())
{
+ throw new IllegalStateException(
+ "The workflow: " + workflowExecutionRunnable.getName()
+ + " does not exist tasks chain which is killed");
+ }
+ super.workflowFinish(workflowExecutionRunnable,
WorkflowExecutionStatus.STOP);
}
@Override
@@ -142,6 +148,16 @@ public class WorkflowRunningStateAction extends
AbstractWorkflowStateAction {
return;
}
+ // [Fix-17354]
+ // If there exist tasks which has set timeout failed, then will
publish a kill event to kill the task.
+ // So there might exist task which is killed, and the workflow
instance state is running.
+ // This is a special case, the workflow instance can transform from
running to stop state.
+ // Is there better way to handle this case?
+ if (workflowExecutionGraph.isExistKilledTaskExecutionRunnableChain()) {
+
workflowEventBus.publish(WorkflowStoppedLifecycleEvent.of(workflowExecutionRunnable));
+ return;
+ }
+
if (workflowExecutionGraph.isAllTaskExecutionRunnableChainSuccess()) {
workflowEventBus.publish(WorkflowSucceedLifecycleEvent.of(workflowExecutionRunnable));
return;
@@ -149,6 +165,6 @@ public class WorkflowRunningStateAction extends
AbstractWorkflowStateAction {
throw new IllegalStateException("The workflow: " +
workflowExecutionRunnable.getName() +
" state is " + workflowExecutionRunnable.getState()
- + " can only finish with success/failed but exist task which
state is not success and failure");
+ + " can only finish with task success/failed/killed but exist
task which state is not success、failure、killed");
}
}
diff --git
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/WorkflowTestCaseContext.java
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/WorkflowTestCaseContext.java
index 0441427d67..35cee61c93 100644
---
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/WorkflowTestCaseContext.java
+++
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/WorkflowTestCaseContext.java
@@ -61,4 +61,14 @@ public class WorkflowTestCaseContext {
}
return workflows.get(0);
}
+
+ public WorkflowDefinition getWorkflow(String name) {
+ if (CollectionUtils.isEmpty(workflows)) {
+ throw new IllegalStateException("workflows is empty");
+ }
+ return workflows.stream()
+ .filter(workflow -> workflow.getName().equals(name))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Workflow with
name " + name + " not found"));
+ }
}
diff --git
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowStartTestCase.java
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowStartTestCase.java
index 4c56976dfd..530b6b7d6f 100644
---
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowStartTestCase.java
+++
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowStartTestCase.java
@@ -1004,4 +1004,35 @@ public class WorkflowStartTestCase extends
AbstractMasterIntegrationTestCase {
});
masterContainer.assertAllResourceReleased();
}
+
+ @Test
+ @DisplayName("Test start a workflow which contains a dep task with timeout
kill strategy")
+ public void testStartWorkflow_withTimeoutKillTask() {
+ final String yaml = "/it/start/workflow_with_timeout_kill_task.yaml";
+ final WorkflowTestCaseContext context =
workflowTestCaseContextFactory.initializeContextFromYaml(yaml);
+ final WorkflowDefinition workflow =
context.getWorkflow("workflow_with_timeout_kill_task");
+
+ final WorkflowOperator.WorkflowTriggerDTO workflowTriggerDTO =
WorkflowOperator.WorkflowTriggerDTO.builder()
+ .workflowDefinition(workflow)
+ .runWorkflowCommandParam(new RunWorkflowCommandParam())
+ .build();
+ workflowOperator.manualTriggerWorkflow(workflowTriggerDTO);
+
+ await()
+ .atMost(Duration.ofSeconds(90))
+ .untilAsserted(() -> {
+ Assertions
+
.assertThat(repository.queryWorkflowInstance(workflow))
+ .satisfiesExactly(workflowInstance ->
assertThat(workflowInstance.getState())
+ .isEqualTo(WorkflowExecutionStatus.STOP));
+ Assertions
+ .assertThat(repository.queryTaskInstance(workflow))
+ .hasSize(1)
+ .satisfiesExactly(taskInstance -> {
+
assertThat(taskInstance.getName()).isEqualTo("dep_task_with_timeout_killed");
+
assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.KILL);
+ });
+ });
+ masterContainer.assertAllResourceReleased();
+ }
}
diff --git
a/dolphinscheduler-master/src/test/resources/it/start/workflow_with_timeout_kill_task.yaml
b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_timeout_kill_task.yaml
new file mode 100644
index 0000000000..a4439c1e68
--- /dev/null
+++
b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_timeout_kill_task.yaml
@@ -0,0 +1,95 @@
+#
+# 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.
+#
+
+project:
+ name: MasterIntegrationTest
+ code: 1
+ description: This is a fake project
+ userId: 1
+ userName: admin
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2021-08-12 00:00:00
+
+workflows:
+ - name: workflow_with_one_fake_task_success
+ code: 1
+ version: 1
+ projectCode: 1
+ description: This is a fake workflow with single task
+ releaseState: ONLINE
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2021-08-12 00:00:00
+ userId: 1
+ executionType: PARALLEL
+ - name: workflow_with_timeout_kill_task
+ code: 2
+ version: 1
+ projectCode: 1
+ description: This is a fake workflow with single timeout task
+ releaseState: ONLINE
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2021-08-12 00:00:00
+ userId: 1
+ executionType: PARALLEL
+
+tasks:
+ - name: B
+ code: 1
+ version: 1
+ projectCode: 1
+ userId: 1
+ taskType: LogicFakeTask
+ taskParams: '{"localParams":[],"shellScript":"if [
\"${system.project.name}\" = \"MasterIntegrationTest\" ]; then\n exit 0
\nelse\n exit 1\nfi","resourceList":[]}'
+ workerGroup: default
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2021-08-12 00:00:00
+ taskExecuteType: BATCH
+ - name: dep_task_with_timeout_killed
+ code: 2
+ version: 1
+ projectCode: 1
+ userId: 1
+ timeoutFlag: 'OPEN'
+ timeoutNotifyStrategy: 'FAILED'
+ timeout: 1
+ taskType: DEPENDENT
+ taskParams:
'{"localParams":[],"resourceList":[],"dependence":{"checkInterval":10,"failurePolicy":"DEPENDENT_FAILURE_FAILURE","relation":"AND","dependTaskList":[{"relation":"AND","dependItemList":[{"dependentType":"DEPENDENT_ON_WORKFLOW","projectCode":1,"definitionCode":1,"depTaskCode":0,"cycle":"day","dateValue":"last1Days"}]}]}}'
+ workerGroup: default
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2021-08-12 00:00:00
+ taskExecuteType: BATCH
+
+taskRelations:
+ - projectCode: 1
+ workflowDefinitionCode: 1
+ workflowDefinitionVersion: 1
+ preTaskCode: 0
+ preTaskVersion: 0
+ postTaskCode: 1
+ postTaskVersion: 1
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2024-08-12 00:00:00
+ - projectCode: 1
+ workflowDefinitionCode: 2
+ workflowDefinitionVersion: 1
+ preTaskCode: 0
+ preTaskVersion: 0
+ postTaskCode: 2
+ postTaskVersion: 1
+ createTime: 2024-08-12 00:00:00
+ updateTime: 2024-08-12 00:00:00
+