@@ -26,6 +26,9 @@ public class RewindTest {
2626 // Flag to control whether the activity should fail (first call fails, subsequent calls succeed)
2727 private static final AtomicBoolean shouldFail = new AtomicBoolean (true );
2828
29+ // Separate flag for sub-orchestration rewind test
30+ private static final AtomicBoolean shouldSubFail = new AtomicBoolean (true );
31+
2932 /**
3033 * HTTP trigger to start the rewindable orchestration.
3134 */
@@ -86,4 +89,74 @@ public HttpResponseMessage resetRewindFailureFlag(
8689 .body ("Failure flag reset to true" )
8790 .build ();
8891 }
92+
93+ // --- Sub-orchestration rewind test functions ---
94+
95+ /**
96+ * HTTP trigger to start the parent orchestration for sub-orchestration rewind test.
97+ */
98+ @ FunctionName ("StartRewindableSubOrchestration" )
99+ public HttpResponseMessage startRewindableSubOrchestration (
100+ @ HttpTrigger (name = "req" , methods = {HttpMethod .GET , HttpMethod .POST }, authLevel = AuthorizationLevel .ANONYMOUS ) HttpRequestMessage <Optional <String >> request ,
101+ @ DurableClientInput (name = "durableContext" ) DurableClientContext durableContext ,
102+ final ExecutionContext context ) {
103+ context .getLogger ().info ("Starting rewindable sub-orchestration test." );
104+
105+ // Reset the sub failure flag so the first activity call will fail
106+ shouldSubFail .set (true );
107+
108+ DurableTaskClient client = durableContext .getClient ();
109+ String instanceId = client .scheduleNewOrchestrationInstance ("RewindableParentOrchestration" );
110+ context .getLogger ().info ("Created parent orchestration with instance ID = " + instanceId );
111+ return durableContext .createCheckStatusResponse (request , instanceId );
112+ }
113+
114+ /**
115+ * Parent orchestration that calls a sub-orchestration which may fail.
116+ */
117+ @ FunctionName ("RewindableParentOrchestration" )
118+ public String rewindableParentOrchestration (
119+ @ DurableOrchestrationTrigger (name = "ctx" ) TaskOrchestrationContext ctx ) {
120+ String result = ctx .callSubOrchestrator ("RewindableChildOrchestration" , "SubRewindTest" , String .class ).await ();
121+ return "Parent:" + result ;
122+ }
123+
124+ /**
125+ * Sub-orchestration that calls an activity which will fail on the first attempt.
126+ */
127+ @ FunctionName ("RewindableChildOrchestration" )
128+ public String rewindableChildOrchestration (
129+ @ DurableOrchestrationTrigger (name = "ctx" ) TaskOrchestrationContext ctx ) {
130+ String result = ctx .callActivity ("FailOnceSubActivity" , "SubRewindTest" , String .class ).await ();
131+ return result ;
132+ }
133+
134+ /**
135+ * Activity for sub-orchestration test that fails on the first call but succeeds on subsequent calls.
136+ */
137+ @ FunctionName ("FailOnceSubActivity" )
138+ public String failOnceSubActivity (
139+ @ DurableActivityTrigger (name = "input" ) String input ,
140+ final ExecutionContext context ) {
141+ if (shouldSubFail .compareAndSet (true , false )) {
142+ context .getLogger ().warning ("FailOnceSubActivity: Simulating failure for input: " + input );
143+ throw new RuntimeException ("Simulated sub-orchestration transient failure - rewind to retry" );
144+ }
145+ context .getLogger ().info ("FailOnceSubActivity: Success for input: " + input );
146+ return input + "-sub-rewound-success" ;
147+ }
148+
149+ /**
150+ * HTTP trigger to reset the sub-orchestration failure flag.
151+ */
152+ @ FunctionName ("ResetSubRewindFailureFlag" )
153+ public HttpResponseMessage resetSubRewindFailureFlag (
154+ @ HttpTrigger (name = "req" , methods = {HttpMethod .POST }, authLevel = AuthorizationLevel .ANONYMOUS ) HttpRequestMessage <Optional <String >> request ,
155+ final ExecutionContext context ) {
156+ shouldSubFail .set (true );
157+ context .getLogger ().info ("Reset sub failure flag to true." );
158+ return request .createResponseBuilder (com .microsoft .azure .functions .HttpStatus .OK )
159+ .body ("Sub failure flag reset to true" )
160+ .build ();
161+ }
89162}
0 commit comments