From d2b863961ea6e903ec7246b2d7ab6f81f70426d2 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 16 Jul 2026 12:59:15 +0200 Subject: [PATCH 1/2] add asyncComplete support to sdk Task base class asyncComplete was present on WorkflowTask but not exposed through the sdk, making it impossible to create async http or event tasks without subclassing as a workaround. adds the field to Task alongside optional and startDelay, wires it through toWorkflowTask() and restores it from the WorkflowTask constructor. any task type can now call .asyncComplete(true). Signed-off-by: klouds27 --- .../conductor/sdk/workflow/def/tasks/Task.java | 13 +++++++++++++ .../sdk/workflow/def/TaskConversionsTests.java | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java index e814c192d..5d5263905 100644 --- a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java +++ b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java @@ -39,6 +39,8 @@ public abstract class Task { private int startDelay; + private boolean asyncComplete; + private final TaskType type; private Map input = new HashMap<>(); @@ -69,6 +71,7 @@ protected Task(WorkflowTask workflowTask) { this.input = workflowTask.getInputParameters(); this.description = workflowTask.getDescription(); this.name = workflowTask.getName(); + this.asyncComplete = Boolean.TRUE.equals(workflowTask.isAsyncComplete()); } public T name(String name) { @@ -81,6 +84,15 @@ public T description(String description) { return (T) this; } + public T asyncComplete(boolean asyncComplete) { + this.asyncComplete = asyncComplete; + return (T) this; + } + + public boolean isAsyncComplete() { + return asyncComplete; + } + public T input(String key, boolean value) { input.put(key, value); return (T) this; @@ -210,6 +222,7 @@ protected final WorkflowTask toWorkflowTask() { workflowTask.setInputParameters(input); workflowTask.setStartDelay(startDelay); workflowTask.setOptional(optional); + workflowTask.setAsyncComplete(asyncComplete); // Let the sub-classes enrich the workflow task before returning back updateWorkflowTask(workflowTask); diff --git a/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java b/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java index e0d044729..0f2f74247 100644 --- a/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java +++ b/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java @@ -460,6 +460,19 @@ public void testHttpConverter() { System.out.println(taskFromWorkflowTask.getInput()); } + @Test + public void testHttpAsyncComplete() { + Http httpTask = new Http("http_ref"); + httpTask.asyncComplete(true); + + WorkflowTask workflowTask = httpTask.getWorkflowDefTasks().get(0); + assertTrue(workflowTask.isAsyncComplete()); + + Task fromWorkflowTask = TaskRegistry.getTask(workflowTask); + assertTrue(fromWorkflowTask instanceof Http); + assertTrue(((Http) fromWorkflowTask).isAsyncComplete()); + } + @Test public void testJQTaskConversion() { JQ jqTask = new JQ("task_name", "{ key3: (.key1.value1 + .key2.value2) }"); From 8a130f28560d804cdc93ba81eaa2adda9def3524 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 5 Aug 2026 16:51:55 +0200 Subject: [PATCH 2/2] scope asyncComplete to Http and Event task types only moves asyncComplete out of the base Task class and into Http and Event, the only task types where waiting on an external completion signal is meaningful. adds Event round-trip test alongside the existing Http test. Signed-off-by: klouds27 --- .../conductor/sdk/workflow/def/tasks/Event.java | 17 +++++++++++++++++ .../conductor/sdk/workflow/def/tasks/Http.java | 13 +++++++++++++ .../conductor/sdk/workflow/def/tasks/Task.java | 13 ------------- .../sdk/workflow/def/TaskConversionsTests.java | 13 +++++++++++++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Event.java b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Event.java index 4911a635d..c5279e559 100644 --- a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Event.java +++ b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Event.java @@ -22,6 +22,8 @@ public class Event extends Task { private static final String SINK_PARAMETER = "sink"; + private boolean asyncComplete; + /** * @param taskReferenceName Unique reference name within the workflow * @param eventSink qualified name of the event sink where the message is published. Using the @@ -38,6 +40,21 @@ public Event(String taskReferenceName, String eventSink) { Event(WorkflowTask workflowTask) { super(workflowTask); + this.asyncComplete = Boolean.TRUE.equals(workflowTask.isAsyncComplete()); + } + + public Event asyncComplete(boolean asyncComplete) { + this.asyncComplete = asyncComplete; + return this; + } + + public boolean isAsyncComplete() { + return asyncComplete; + } + + @Override + protected void updateWorkflowTask(WorkflowTask workflowTask) { + workflowTask.setAsyncComplete(asyncComplete); } public String getSink() { diff --git a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Http.java b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Http.java index 37468ff1c..3cb133b37 100644 --- a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Http.java +++ b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Http.java @@ -34,6 +34,8 @@ public class Http extends Task { private final ObjectMapper objectMapper = new ObjectMapperProvider().getObjectMapper(); + private boolean asyncComplete; + private Input httpRequest; public Http(String taskReferenceName) { @@ -45,6 +47,7 @@ public Http(String taskReferenceName) { Http(WorkflowTask workflowTask) { super(workflowTask); + this.asyncComplete = Boolean.TRUE.equals(workflowTask.isAsyncComplete()); Object inputRequest = workflowTask.getInputParameters().get(INPUT_PARAM); if (inputRequest != null) { @@ -56,6 +59,15 @@ public Http(String taskReferenceName) { } } + public Http asyncComplete(boolean asyncComplete) { + this.asyncComplete = asyncComplete; + return this; + } + + public boolean isAsyncComplete() { + return asyncComplete; + } + public Http input(Input httpRequest) { this.httpRequest = httpRequest; return this; @@ -92,6 +104,7 @@ public Input getHttpRequest() { @Override protected void updateWorkflowTask(WorkflowTask workflowTask) { + workflowTask.setAsyncComplete(asyncComplete); workflowTask.getInputParameters().put(INPUT_PARAM, httpRequest); } diff --git a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java index 5d5263905..e814c192d 100644 --- a/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java +++ b/conductor-client/src/main/java/com/netflix/conductor/sdk/workflow/def/tasks/Task.java @@ -39,8 +39,6 @@ public abstract class Task { private int startDelay; - private boolean asyncComplete; - private final TaskType type; private Map input = new HashMap<>(); @@ -71,7 +69,6 @@ protected Task(WorkflowTask workflowTask) { this.input = workflowTask.getInputParameters(); this.description = workflowTask.getDescription(); this.name = workflowTask.getName(); - this.asyncComplete = Boolean.TRUE.equals(workflowTask.isAsyncComplete()); } public T name(String name) { @@ -84,15 +81,6 @@ public T description(String description) { return (T) this; } - public T asyncComplete(boolean asyncComplete) { - this.asyncComplete = asyncComplete; - return (T) this; - } - - public boolean isAsyncComplete() { - return asyncComplete; - } - public T input(String key, boolean value) { input.put(key, value); return (T) this; @@ -222,7 +210,6 @@ protected final WorkflowTask toWorkflowTask() { workflowTask.setInputParameters(input); workflowTask.setStartDelay(startDelay); workflowTask.setOptional(optional); - workflowTask.setAsyncComplete(asyncComplete); // Let the sub-classes enrich the workflow task before returning back updateWorkflowTask(workflowTask); diff --git a/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java b/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java index 0f2f74247..1ced27725 100644 --- a/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java +++ b/conductor-client/src/test/java/com/netflix/conductor/sdk/workflow/def/TaskConversionsTests.java @@ -473,6 +473,19 @@ public void testHttpAsyncComplete() { assertTrue(((Http) fromWorkflowTask).isAsyncComplete()); } + @Test + public void testEventAsyncComplete() { + Event eventTask = new Event("event_ref", "sqs:my-queue"); + eventTask.asyncComplete(true); + + WorkflowTask workflowTask = eventTask.getWorkflowDefTasks().get(0); + assertTrue(workflowTask.isAsyncComplete()); + + Task fromWorkflowTask = TaskRegistry.getTask(workflowTask); + assertTrue(fromWorkflowTask instanceof Event); + assertTrue(((Event) fromWorkflowTask).isAsyncComplete()); + } + @Test public void testJQTaskConversion() { JQ jqTask = new JQ("task_name", "{ key3: (.key1.value1 + .key2.value2) }");