33package io .durabletask .samples ;
44
55import com .microsoft .durabletask .*;
6- import lombok .experimental .Delegate ;
76
87import javax .annotation .Nullable ;
98import java .io .IOException ;
109import java .time .Duration ;
1110import java .util .concurrent .TimeoutException ;
1211
1312/**
14- * Demonstrates how to wrap {@link TaskOrchestrationContext} and forward
15- * {@link TaskOrchestrationContext#getParentInstance()} through the wrapper so that
16- * helper methods built on top of the wrapped context can observe the parent
17- * orchestration (if any).
18- *
19- * <p>This mirrors the .NET {@code ReplaySafeLoggerFactorySample} pattern, where the
20- * wrapping context explicitly forwards the abstract {@code Parent} property.
13+ * Demonstrates {@link TaskOrchestrationContext#getParentInstance()}: the child orchestration
14+ * reports its parent when started as a sub-orchestration, and reports {@code null} when started
15+ * standalone.
2116 *
2217 * <p>Run with: {@code ./gradlew runParentInstanceSample}
2318 */
@@ -33,28 +28,26 @@ public static void main(String[] args) throws IOException, InterruptedException,
3328 @ Override
3429 public TaskOrchestration create () {
3530 return ctx -> {
36- LoggingTaskOrchestrationContext wrapped = new LoggingTaskOrchestrationContext (ctx );
37- wrapped .log ("Starting child sub-orchestration..." );
38- String childResult = wrapped .callSubOrchestrator (
31+ log (ctx , "Starting child sub-orchestration..." );
32+ String childResult = ctx .callSubOrchestrator (
3933 "ChildOrchestrator" , null , String .class ).await ();
40- wrapped . log ("Child returned: " + childResult );
41- wrapped .complete (childResult );
34+ log (ctx , "Child returned: " + childResult );
35+ ctx .complete (childResult );
4236 };
4337 }
4438 });
4539
46- // Child orchestration: uses the wrapper helper that reports the parent .
40+ // Child orchestration: reads getParentInstance() directly on the context .
4741 workerBuilder .addOrchestration (new TaskOrchestrationFactory () {
4842 @ Override
4943 public String getName () { return "ChildOrchestrator" ; }
5044
5145 @ Override
5246 public TaskOrchestration create () {
5347 return ctx -> {
54- LoggingTaskOrchestrationContext wrapped = new LoggingTaskOrchestrationContext (ctx );
55- String result = wrapped .describeParent ();
56- wrapped .log (result );
57- wrapped .complete (result );
48+ String result = describeParent (ctx .getParentInstance ());
49+ log (ctx , result );
50+ ctx .complete (result );
5851 };
5952 }
6053 });
@@ -64,7 +57,7 @@ public TaskOrchestration create() {
6457
6558 DurableTaskClient client = SampleUtils .newClientBuilder ().build ();
6659
67- // Step 1: Start the parent. The child observes its parent through the wrapper .
60+ // Step 1: Start the parent. The child observes its parent via getParentInstance() .
6861 System .out .println ("=== Step 1: Sub-orchestration (child has parent) ===" );
6962 String parentId = client .scheduleNewOrchestrationInstance ("ParentOrchestrator" );
7063 System .out .println (" Scheduled ParentOrchestrator: " + parentId );
@@ -89,42 +82,19 @@ public TaskOrchestration create() {
8982 worker .stop ();
9083 }
9184
92- /**
93- * Wrapper that forwards every {@link TaskOrchestrationContext} member to an inner
94- * context and exposes replay-safe helpers built on top of it.
95- *
96- * <p>Because {@link TaskOrchestrationContext#getParentInstance()} is abstract,
97- * any wrapper must explicitly forward it. Here we let Lombok {@code @Delegate}
98- * generate the forwarding for every method, including {@code getParentInstance()}.
99- * The {@link #describeParent()} and {@link #log(String)} helpers then build on
100- * the wrapped context without breaking replay safety.
101- */
102- static final class LoggingTaskOrchestrationContext implements TaskOrchestrationContext {
103- @ Delegate (types = TaskOrchestrationContext .class )
104- private final TaskOrchestrationContext inner ;
105-
106- LoggingTaskOrchestrationContext (TaskOrchestrationContext inner ) {
107- if (inner == null ) {
108- throw new IllegalArgumentException ("inner must not be null" );
109- }
110- this .inner = inner ;
111- }
112-
113- /** Returns a string describing this orchestration's parent, or that it has none. */
114- String describeParent () {
115- @ Nullable ParentOrchestrationInstance parent = inner .getParentInstance ();
116- if (parent != null ) {
117- return String .format ("I was called by '%s' (instance: %s)" ,
118- parent .getName (), parent .getInstanceId ());
119- }
120- return "No parent — I was started standalone" ;
85+ /** Returns a string describing the given parent instance, or that there is none. */
86+ private static String describeParent (@ Nullable ParentOrchestrationInstance parent ) {
87+ if (parent != null ) {
88+ return String .format ("I was called by '%s' (instance: %s)" ,
89+ parent .getName (), parent .getInstanceId ());
12190 }
91+ return "No parent — I was started standalone" ;
92+ }
12293
123- /** Replay-safe console log. */
124- void log (String message ) {
125- if (!inner .getIsReplaying ()) {
126- System .out .println (" [" + inner .getName () + "] " + message );
127- }
94+ /** Replay-safe console log. */
95+ private static void log (TaskOrchestrationContext ctx , String message ) {
96+ if (!ctx .getIsReplaying ()) {
97+ System .out .println (" [" + ctx .getName () + "] " + message );
12898 }
12999 }
130100}
0 commit comments