From 3492e6ea354e0ac0a5f0b34a2ba8a6574a79f5cf Mon Sep 17 00:00:00 2001 From: Boyan Georgiev Date: Wed, 27 Sep 2023 19:21:01 +0300 Subject: [PATCH] Introducing a Noop task to allow for switch decision branches to have "no" tasks Purpose: When using Switch tasks in usecases where we want a consistent set of decision case branches across all workflows, but some workflows make use of a sub-set of all decision cases, then some decision cases will not have tasks. Because of the constraint to always have tasks in decision cases, this Noop task is required. This task is a system task and autocompletes. --- .../common/metadata/tasks/TaskType.java | 4 +- .../core/execution/mapper/NoopTaskMapper.java | 46 +++++++++++++++ .../conductor/core/execution/tasks/Noop.java | 36 ++++++++++++ .../execution/mapper/NoopTaskMapperTest.java | 57 +++++++++++++++++++ .../core/execution/tasks/TestNoop.java | 36 ++++++++++++ 5 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java create mode 100644 core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java create mode 100644 core/src/test/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapperTest.java create mode 100644 core/src/test/java/com/netflix/conductor/core/execution/tasks/TestNoop.java diff --git a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java index 58df74569f..235a0ac91b 100644 --- a/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java +++ b/common/src/main/java/com/netflix/conductor/common/metadata/tasks/TaskType.java @@ -40,7 +40,8 @@ public enum TaskType { TERMINATE, KAFKA_PUBLISH, JSON_JQ_TRANSFORM, - SET_VARIABLE; + SET_VARIABLE, + NOOP; /** * TaskType constants representing each of the possible enumeration values. Motivation: to not @@ -69,6 +70,7 @@ public enum TaskType { public static final String TASK_TYPE_JSON_JQ_TRANSFORM = "JSON_JQ_TRANSFORM"; public static final String TASK_TYPE_SET_VARIABLE = "SET_VARIABLE"; public static final String TASK_TYPE_FORK = "FORK"; + public static final String TASK_TYPE_NOOP = "NOOP"; private static final Set BUILT_IN_TASKS = new HashSet<>(); diff --git a/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java b/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java new file mode 100644 index 0000000000..a7f9045820 --- /dev/null +++ b/core/src/main/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapper.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 Netflix, Inc. + *

+ * Licensed 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 com.netflix.conductor.core.execution.mapper; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.netflix.conductor.common.metadata.tasks.TaskType; +import com.netflix.conductor.model.TaskModel; + +import static com.netflix.conductor.common.metadata.tasks.TaskType.*; + +@Component +public class NoopTaskMapper implements TaskMapper { + + public static final Logger logger = LoggerFactory.getLogger(NoopTaskMapper.class); + + @Override + public String getTaskType() { + return TaskType.NOOP.name(); + } + + @Override + public List getMappedTasks(TaskMapperContext taskMapperContext) { + logger.debug("TaskMapperContext {} in NoopTaskMapper", taskMapperContext); + + TaskModel task = taskMapperContext.createTaskModel(); + task.setTaskType(TASK_TYPE_NOOP); + task.setStartTime(System.currentTimeMillis()); + task.setStatus(TaskModel.Status.IN_PROGRESS); + return List.of(task); + } +} diff --git a/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java new file mode 100644 index 0000000000..4b9de40a20 --- /dev/null +++ b/core/src/main/java/com/netflix/conductor/core/execution/tasks/Noop.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023 Netflix, Inc. + *

+ * Licensed 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 com.netflix.conductor.core.execution.tasks; + +import org.springframework.stereotype.Component; + +import com.netflix.conductor.core.execution.WorkflowExecutor; +import com.netflix.conductor.model.TaskModel; +import com.netflix.conductor.model.WorkflowModel; + +import static com.netflix.conductor.common.metadata.tasks.TaskType.TASK_TYPE_NOOP; + +@Component(TASK_TYPE_NOOP) +public class Noop extends WorkflowSystemTask { + + public Noop() { + super(TASK_TYPE_NOOP); + } + + @Override + public boolean execute( + WorkflowModel workflow, TaskModel task, WorkflowExecutor workflowExecutor) { + task.setStatus(TaskModel.Status.COMPLETED); + return true; + } +} diff --git a/core/src/test/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapperTest.java b/core/src/test/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapperTest.java new file mode 100644 index 0000000000..6c89af44f9 --- /dev/null +++ b/core/src/test/java/com/netflix/conductor/core/execution/mapper/NoopTaskMapperTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2023 Netflix, Inc. + *

+ * Licensed 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 com.netflix.conductor.core.execution.mapper; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.netflix.conductor.common.metadata.tasks.TaskDef; +import com.netflix.conductor.common.metadata.tasks.TaskType; +import com.netflix.conductor.common.metadata.workflow.WorkflowDef; +import com.netflix.conductor.common.metadata.workflow.WorkflowTask; +import com.netflix.conductor.core.utils.IDGenerator; +import com.netflix.conductor.model.TaskModel; +import com.netflix.conductor.model.WorkflowModel; + +public class NoopTaskMapperTest { + + @Test + public void getMappedTasks() { + + WorkflowTask workflowTask = new WorkflowTask(); + workflowTask.setType(TaskType.TASK_TYPE_NOOP); + + String taskId = new IDGenerator().generate(); + + WorkflowDef workflowDef = new WorkflowDef(); + WorkflowModel workflow = new WorkflowModel(); + workflow.setWorkflowDefinition(workflowDef); + + TaskMapperContext taskMapperContext = + TaskMapperContext.newBuilder() + .withWorkflowModel(workflow) + .withTaskDefinition(new TaskDef()) + .withWorkflowTask(workflowTask) + .withRetryCount(0) + .withTaskId(taskId) + .build(); + + List mappedTasks = new NoopTaskMapper().getMappedTasks(taskMapperContext); + + Assert.assertNotNull(mappedTasks); + Assert.assertEquals(1, mappedTasks.size()); + Assert.assertEquals(TaskType.TASK_TYPE_NOOP, mappedTasks.get(0).getTaskType()); + } +} diff --git a/core/src/test/java/com/netflix/conductor/core/execution/tasks/TestNoop.java b/core/src/test/java/com/netflix/conductor/core/execution/tasks/TestNoop.java new file mode 100644 index 0000000000..1767f84ec9 --- /dev/null +++ b/core/src/test/java/com/netflix/conductor/core/execution/tasks/TestNoop.java @@ -0,0 +1,36 @@ +/* + * Copyright 2023 Netflix, Inc. + *

+ * Licensed 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 com.netflix.conductor.core.execution.tasks; + +import org.junit.Test; + +import com.netflix.conductor.core.execution.WorkflowExecutor; +import com.netflix.conductor.model.TaskModel; +import com.netflix.conductor.model.WorkflowModel; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class TestNoop { + + private final WorkflowExecutor executor = mock(WorkflowExecutor.class); + + @Test + public void should_do_nothing() { + WorkflowModel workflow = new WorkflowModel(); + Noop noopTask = new Noop(); + TaskModel task = new TaskModel(); + noopTask.execute(workflow, task, executor); + assertEquals(TaskModel.Status.COMPLETED, task.getStatus()); + } +}