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 3f168cce6e30..1c3af50915dc 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 @@ -80,11 +80,27 @@ public interface IWorkflowExecutionGraph { */ boolean isTaskExecutionRunnableActive(final ITaskExecutionRunnable taskExecutionRunnable); + /** + * Whether the given task is inactive. + *

A task is inactive means the task has been `executed`. + */ + boolean isTaskExecutionRunnableInActive(final ITaskExecutionRunnable taskExecutionRunnable); + /** * Whether the given task is killed. */ boolean isTaskExecutionRunnableKilled(final ITaskExecutionRunnable taskExecutionRunnable); + /** + * Whether the given task is failure. + */ + boolean isTaskExecutionRunnableFailed(final ITaskExecutionRunnable taskExecutionRunnable); + + /** + * Whether the given task is paused. + */ + boolean isTaskExecutionRunnablePaused(final ITaskExecutionRunnable taskExecutionRunnable); + /** * Get the active TaskExecutionRunnable list. *

The active TaskExecutionRunnable means the task is handling in the workflow execution graph. @@ -176,6 +192,7 @@ public interface IWorkflowExecutionGraph { * Check whether the given task is the end of the task chain. *

If the given task has no successor, then it is the end of the task chain. *

If the given task is killed or paused, then it is the end of the task chain. + *

If the given task is failure, and all its successors are condition task then it is not end of a task chain. */ boolean isEndOfTaskChain(final ITaskExecutionRunnable taskExecutionRunnable); 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 dd89debe6c64..2439d9f840ae 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 @@ -51,6 +51,8 @@ public class WorkflowExecutionGraph implements IWorkflowExecutionGraph { private final Set activeTaskExecutionRunnable; + private final Set inActiveTaskExecutionRunnable; + public WorkflowExecutionGraph() { this.failureTaskChains = new HashSet<>(); this.pausedTaskChains = new HashSet<>(); @@ -60,6 +62,7 @@ public WorkflowExecutionGraph() { this.successors = new HashMap<>(); this.totalTaskExecuteRunnableMap = new HashMap<>(); this.activeTaskExecutionRunnable = new HashSet<>(); + this.inActiveTaskExecutionRunnable = new HashSet<>(); } @Override @@ -143,11 +146,26 @@ public boolean isTaskExecutionRunnableActive(final ITaskExecutionRunnable taskEx return activeTaskExecutionRunnable.contains(taskExecutionRunnable.getName()); } + @Override + public boolean isTaskExecutionRunnableInActive(ITaskExecutionRunnable taskExecutionRunnable) { + return inActiveTaskExecutionRunnable.contains(taskExecutionRunnable.getName()); + } + @Override public boolean isTaskExecutionRunnableKilled(final ITaskExecutionRunnable taskExecutionRunnable) { return killedTaskChains.contains(taskExecutionRunnable.getName()); } + @Override + public boolean isTaskExecutionRunnableFailed(ITaskExecutionRunnable taskExecutionRunnable) { + return failureTaskChains.contains(taskExecutionRunnable.getName()); + } + + @Override + public boolean isTaskExecutionRunnablePaused(ITaskExecutionRunnable taskExecutionRunnable) { + return pausedTaskChains.contains(taskExecutionRunnable.getName()); + } + @Override public List getActiveTaskExecutionRunnable() { return activeTaskExecutionRunnable @@ -165,10 +183,10 @@ public List getAllTaskExecutionRunnable() { public boolean isTriggerConditionMet(final ITaskExecutionRunnable taskExecutionRunnable) { return getPredecessors(taskExecutionRunnable.getName()) .stream() - .allMatch(predecessor -> isTaskFinish(predecessor) - && !isTaskFailure(predecessor) - && !isTaskPaused(predecessor) - && !isTaskKilled(predecessor)); + .allMatch(predecessor -> isTaskExecutionRunnableInActive(predecessor) + && !isTaskExecutionRunnableFailed(predecessor) + && !isTaskExecutionRunnablePaused(predecessor) + && !isTaskExecutionRunnableKilled(predecessor)); } @Override @@ -209,6 +227,7 @@ public void markTaskExecutionRunnableActive(final ITaskExecutionRunnable taskExe @Override public void markTaskExecutionRunnableInActive(final ITaskExecutionRunnable taskExecutionRunnable) { activeTaskExecutionRunnable.remove(taskExecutionRunnable.getName()); + inActiveTaskExecutionRunnable.add(taskExecutionRunnable.getName()); } @Override @@ -242,8 +261,9 @@ public void markTaskSkipped(final String taskName) { @Override public boolean isEndOfTaskChain(final ITaskExecutionRunnable taskExecutionRunnable) { return successors.get(taskExecutionRunnable.getName()).isEmpty() - || killedTaskChains.contains(taskExecutionRunnable.getName()) - || pausedTaskChains.contains(taskExecutionRunnable.getName()); + || isTaskExecutionRunnableKilled(taskExecutionRunnable) + || isTaskExecutionRunnablePaused(taskExecutionRunnable) + || isTaskExecutionRunnableFailed(taskExecutionRunnable); } @Override @@ -291,22 +311,6 @@ public boolean isAllSuccessorsAreConditionTask(final ITaskExecutionRunnable task || TaskTypeUtils.isConditionTask(taskExecutionRunnable.getTaskInstance().getTaskType())); } - private boolean isTaskFinish(final ITaskExecutionRunnable taskExecutionRunnable) { - return !activeTaskExecutionRunnable.contains(taskExecutionRunnable.getName()); - } - - private boolean isTaskFailure(final ITaskExecutionRunnable taskExecutionRunnable) { - return failureTaskChains.contains(taskExecutionRunnable.getName()); - } - - private boolean isTaskPaused(final ITaskExecutionRunnable taskExecutionRunnable) { - return pausedTaskChains.contains(taskExecutionRunnable.getName()); - } - - private boolean isTaskKilled(final ITaskExecutionRunnable taskExecutionRunnable) { - return killedTaskChains.contains(taskExecutionRunnable.getName()); - } - private void assertTaskExecutionRunnableState(final ITaskExecutionRunnable taskExecutionRunnable, final TaskExecutionStatus taskExecutionStatus) { final TaskInstance taskInstance = taskExecutionRunnable.getTaskInstance(); diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java index 1cd6ad21b72e..4e05255d6426 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java @@ -115,8 +115,8 @@ protected void pauseActiveTask(final IWorkflowExecutionRunnable workflowExecutio } } - protected void onTaskFinish(final IWorkflowExecutionRunnable workflowExecutionRunnable, - final ITaskExecutionRunnable taskExecutionRunnable) { + protected void tryToTriggerSuccessorsAfterTaskFinish(final IWorkflowExecutionRunnable workflowExecutionRunnable, + final ITaskExecutionRunnable taskExecutionRunnable) { final IWorkflowExecutionGraph workflowExecutionGraph = workflowExecutionRunnable.getWorkflowExecutionGraph(); if (workflowExecutionGraph.isEndOfTaskChain(taskExecutionRunnable)) { emitWorkflowFinishedEventIfApplicable(workflowExecutionRunnable); 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 1d1925f272f5..cb48b33acde2 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 @@ -52,7 +52,7 @@ public void startEventAction(final IWorkflowExecutionRunnable workflowExecutionR public void topologyLogicalTransitionEventAction(final IWorkflowExecutionRunnable workflowExecutionRunnable, final WorkflowTopologyLogicalTransitionWithTaskFinishLifecycleEvent workflowTopologyLogicalTransitionWithTaskFinishEvent) { throwExceptionIfStateIsNotMatch(workflowExecutionRunnable); - super.onTaskFinish(workflowExecutionRunnable, + super.tryToTriggerSuccessorsAfterTaskFinish(workflowExecutionRunnable, workflowTopologyLogicalTransitionWithTaskFinishEvent.getTaskExecutionRunnable()); } 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 8b1f393ffe63..c5c94c18c588 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 @@ -52,7 +52,7 @@ public void startEventAction(final IWorkflowExecutionRunnable workflowExecutionR public void topologyLogicalTransitionEventAction(final IWorkflowExecutionRunnable workflowExecutionRunnable, final WorkflowTopologyLogicalTransitionWithTaskFinishLifecycleEvent workflowTopologyLogicalTransitionWithTaskFinishEvent) { throwExceptionIfStateIsNotMatch(workflowExecutionRunnable); - super.onTaskFinish(workflowExecutionRunnable, + super.tryToTriggerSuccessorsAfterTaskFinish(workflowExecutionRunnable, workflowTopologyLogicalTransitionWithTaskFinishEvent.getTaskExecutionRunnable()); } 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 2ef810aba452..15e360cdb614 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 @@ -53,7 +53,7 @@ public void topologyLogicalTransitionEventAction( final IWorkflowExecutionRunnable workflowExecutionRunnable, final WorkflowTopologyLogicalTransitionWithTaskFinishLifecycleEvent workflowTopologyLogicalTransitionWithTaskFinishEvent) { throwExceptionIfStateIsNotMatch(workflowExecutionRunnable); - super.onTaskFinish(workflowExecutionRunnable, + super.tryToTriggerSuccessorsAfterTaskFinish(workflowExecutionRunnable, workflowTopologyLogicalTransitionWithTaskFinishEvent.getTaskExecutionRunnable()); } 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 55558eece228..1041a34a521e 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 @@ -252,6 +252,90 @@ public void testStartWorkflow_with_subWorkflowTask_dryRunSuccess() { masterContainer.assertAllResourceReleased(); } + @Test + @DisplayName("Test start a workflow with one fake task(A) with multiple predecessors run success") + void testStartWorkflow_with_oneTaskWithMultiplePredecessors_runSuccess() { + final String yaml = "/it/start/workflow_with_one_fake_task_with_multiple_predecessors_success.yaml"; + final WorkflowTestCaseContext context = workflowTestCaseContextFactory.initializeContextFromYaml(yaml); + final WorkflowDefinition parentWorkflow = context.getOneWorkflow(); + + final WorkflowOperator.WorkflowTriggerDTO workflowTriggerDTO = WorkflowOperator.WorkflowTriggerDTO.builder() + .workflowDefinition(parentWorkflow) + .runWorkflowCommandParam(new RunWorkflowCommandParam()) + .build(); + final Integer workflowInstanceId = workflowOperator.manualTriggerWorkflow(workflowTriggerDTO); + + await() + .atMost(Duration.ofMinutes(1)) + .untilAsserted(() -> { + Assertions + .assertThat(repository.queryWorkflowInstance(workflowInstanceId)) + .matches( + workflowInstance -> workflowInstance.getState() == WorkflowExecutionStatus.SUCCESS); + + Assertions + .assertThat(repository.queryTaskInstance(workflowInstanceId)) + .hasSize(4) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("A"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("B"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("C"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("D"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }); + }); + masterContainer.assertAllResourceReleased(); + } + + @Test + @DisplayName("Test start a workflow with one fake task(A) with multiple predecessors run failed") + void testStartWorkflow_with_oneTaskWithMultiplePredecessors_runFailed() { + final String yaml = "/it/start/workflow_with_one_fake_task_with_multiple_predecessors_failed.yaml"; + final WorkflowTestCaseContext context = workflowTestCaseContextFactory.initializeContextFromYaml(yaml); + final WorkflowDefinition parentWorkflow = context.getOneWorkflow(); + + final WorkflowOperator.WorkflowTriggerDTO workflowTriggerDTO = WorkflowOperator.WorkflowTriggerDTO.builder() + .workflowDefinition(parentWorkflow) + .runWorkflowCommandParam(new RunWorkflowCommandParam()) + .build(); + final Integer workflowInstanceId = workflowOperator.manualTriggerWorkflow(workflowTriggerDTO); + + await() + .atMost(Duration.ofMinutes(1)) + .untilAsserted(() -> { + Assertions + .assertThat(repository.queryWorkflowInstance(workflowInstanceId)) + .matches( + workflowInstance -> workflowInstance.getState() == WorkflowExecutionStatus.FAILURE); + + Assertions + .assertThat(repository.queryTaskInstance(workflowInstanceId)) + .hasSize(3) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("A"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("B"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.FAILURE); + }) + .anySatisfy(taskInstance -> { + assertThat(taskInstance.getName()).isEqualTo("C"); + assertThat(taskInstance.getState()).isEqualTo(TaskExecutionStatus.SUCCESS); + }); + }); + masterContainer.assertAllResourceReleased(); + } + @Test @DisplayName("Test start a workflow with one sub workflow task(A) failed") public void testStartWorkflow_with_subWorkflowTask_failed() { diff --git a/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_failed.yaml b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_failed.yaml new file mode 100644 index 000000000000..075a45da337c --- /dev/null +++ b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_failed.yaml @@ -0,0 +1,132 @@ +# +# 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. +# + +# A(success) -> B(failed) -> D(success) +# C(success) -> D(success) +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_with_multiple_predecessors_failed + code: 1 + version: 1 + projectCode: 1 + description: This is a fake workflow with one task which has multiple predecessors + releaseState: ONLINE + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + userId: 1 + executionType: PARALLEL + +tasks: + - name: A + code: 1 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"sleep 2"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: B + code: 2 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"xx"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: C + code: 3 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"echo success"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: D + code: 4 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"echo success"}' + 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: 1 + workflowDefinitionVersion: 1 + preTaskCode: 1 + preTaskVersion: 1 + postTaskCode: 2 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 2 + preTaskVersion: 1 + postTaskCode: 4 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 0 + preTaskVersion: 0 + postTaskCode: 3 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 3 + preTaskVersion: 1 + postTaskCode: 4 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 diff --git a/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_success.yaml b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_success.yaml new file mode 100644 index 000000000000..53cc326986ac --- /dev/null +++ b/dolphinscheduler-master/src/test/resources/it/start/workflow_with_one_fake_task_with_multiple_predecessors_success.yaml @@ -0,0 +1,132 @@ +# +# 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. +# + +# A(success) -> B(success) -> D(success) +# C(success) -> D(success) +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_with_multiple_predecessors_success + code: 1 + version: 1 + projectCode: 1 + description: This is a fake workflow with one task which has multiple predecessors + releaseState: ONLINE + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + userId: 1 + executionType: PARALLEL + +tasks: + - name: A + code: 1 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"sleep 2"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: B + code: 2 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"echo success"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: C + code: 3 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"echo success"}' + workerGroup: default + createTime: 2024-08-12 00:00:00 + updateTime: 2021-08-12 00:00:00 + taskExecuteType: BATCH + - name: D + code: 4 + version: 1 + projectCode: 1 + userId: 1 + taskType: LogicFakeTask + taskParams: '{"localParams":null,"varPool":[],"shellScript":"echo success"}' + 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: 1 + workflowDefinitionVersion: 1 + preTaskCode: 1 + preTaskVersion: 1 + postTaskCode: 2 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 2 + preTaskVersion: 1 + postTaskCode: 4 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 0 + preTaskVersion: 0 + postTaskCode: 3 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00 + - projectCode: 1 + workflowDefinitionCode: 1 + workflowDefinitionVersion: 1 + preTaskCode: 3 + preTaskVersion: 1 + postTaskCode: 4 + postTaskVersion: 1 + createTime: 2024-08-12 00:00:00 + updateTime: 2024-08-12 00:00:00