Skip to content

Commit f17d006

Browse files
committed
Remove rewind tests from standalone SDK and keep Functions e2e tests
1 parent cdefa97 commit f17d006

File tree

5 files changed

+20
-294
lines changed

5 files changed

+20
-294
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Unreleased
22

3-
* Adding rewind client API ([#253](https://github.com/microsoft/durabletask-java/pull/253))
3+
* Adding rewind client API ([#253](https://github.com/microsoft/durabletask-java/pull/253)). Note: orchestration processing for rewind is supported with Azure Functions but not with the standalone `GrpcDurableTaskWorker`.
44

55
## v1.7.0
66
* Add descriptive error when orchestration type is not registered ([#261](https://github.com/microsoft/durabletask-java/pull/261))

client/src/main/java/com/microsoft/durabletask/DurableTaskClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ public abstract OrchestrationMetadata waitForInstanceCompletion(
299299
* When rewound, the orchestration instance will restart from the point of failure as if the failure
300300
* never occurred. It rewinds the orchestration by replaying any
301301
* Failed Activities and Failed suborchestrations that themselves have Failed Activities
302+
* <p>
303+
* <b>Note:</b> Rewind requires a backend that supports it. When using Azure Functions with the
304+
* Durable Task extension, rewind is fully supported. The standalone {@code GrpcDurableTaskWorker}
305+
* does not currently support orchestration processing for rewind.
302306
*
303307
* @param instanceId the ID of the orchestration instance to rewind
304308
*/
@@ -313,6 +317,10 @@ public void rewindInstance(String instanceId) {
313317
* When rewound, the orchestration instance will restart from the point of failure as if the failure
314318
* never occurred. It rewinds the orchestration by replaying any
315319
* Failed Activities and Failed suborchestrations that themselves have Failed Activities
320+
* <p>
321+
* <b>Note:</b> Rewind requires a backend that supports it. When using Azure Functions with the
322+
* Durable Task extension, rewind is fully supported. The standalone {@code GrpcDurableTaskWorker}
323+
* does not currently support orchestration processing for rewind.
316324
*
317325
* @param instanceId the ID of the orchestration instance to rewind
318326
* @param reason the reason for rewinding the orchestration instance

client/src/main/java/com/microsoft/durabletask/DurableTaskGrpcClient.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -343,17 +343,6 @@ public PurgeResult purgeInstances(PurgeInstanceCriteria purgeInstanceCriteria) t
343343
}
344344
}
345345

346-
@Override
347-
public void rewindInstance(String instanceId, @Nullable String reason) {
348-
Helpers.throwIfArgumentNull(instanceId, "instanceId");
349-
RewindInstanceRequest.Builder rewindRequestBuilder = RewindInstanceRequest.newBuilder();
350-
rewindRequestBuilder.setInstanceId(instanceId);
351-
if (reason != null) {
352-
rewindRequestBuilder.setReason(StringValue.of(reason));
353-
}
354-
this.sidecarClient.rewindInstance(rewindRequestBuilder.build());
355-
}
356-
357346
@Override
358347
public void suspendInstance(String instanceId, @Nullable String reason) {
359348
SuspendRequest.Builder suspendRequestBuilder = SuspendRequest.newBuilder();
@@ -374,6 +363,17 @@ public void resumeInstance(String instanceId, @Nullable String reason) {
374363
this.sidecarClient.resumeInstance(resumeRequestBuilder.build());
375364
}
376365

366+
@Override
367+
public void rewindInstance(String instanceId, @Nullable String reason) {
368+
Helpers.throwIfArgumentNull(instanceId, "instanceId");
369+
RewindInstanceRequest.Builder rewindRequestBuilder = RewindInstanceRequest.newBuilder();
370+
rewindRequestBuilder.setInstanceId(instanceId);
371+
if (reason != null) {
372+
rewindRequestBuilder.setReason(StringValue.of(reason));
373+
}
374+
this.sidecarClient.rewindInstance(rewindRequestBuilder.build());
375+
}
376+
377377
@Override
378378
public String restartInstance(String instanceId, boolean restartWithNewInstanceId) {
379379
OrchestrationMetadata metadata = this.getInstanceMetadata(instanceId, true);

client/src/test/java/com/microsoft/durabletask/IntegrationTests.java

Lines changed: 0 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -413,56 +413,6 @@ void subOrchestration() throws TimeoutException {
413413
}
414414
}
415415

416-
@Test
417-
void subOrchestrationWithFailedActivity() throws TimeoutException {
418-
final String parentOrchestratorName = "ParentOrchestration";
419-
final String childOrchestratorName = "ChildOrchestration";
420-
final String activityName = "FailingActivity";
421-
final String failureMessage = "Simulated activity failure in sub-orchestration";
422-
final String expectedOutput = "Success after rewind";
423-
final AtomicBoolean shouldFail = new AtomicBoolean(true);
424-
425-
DurableTaskGrpcWorker worker = this.createWorkerBuilder()
426-
.addOrchestrator(parentOrchestratorName, ctx -> {
427-
String result = ctx.callSubOrchestrator(childOrchestratorName, null, String.class).await();
428-
ctx.complete(result);
429-
})
430-
.addOrchestrator(childOrchestratorName, ctx -> {
431-
String result = ctx.callActivity(activityName, null, String.class).await();
432-
ctx.complete(result);
433-
})
434-
.addActivity(activityName, ctx -> {
435-
if (shouldFail.compareAndSet(true, false)) {
436-
throw new RuntimeException(failureMessage);
437-
}
438-
return expectedOutput;
439-
})
440-
.buildAndStart();
441-
442-
DurableTaskClient client = this.createClientBuilder().build();
443-
try (worker; client) {
444-
String instanceId = client.scheduleNewOrchestrationInstance(parentOrchestratorName);
445-
446-
// Wait for the orchestration to fail due to the activity failure in the sub-orchestration
447-
OrchestrationMetadata instance = client.waitForInstanceCompletion(instanceId, defaultTimeout, true);
448-
assertNotNull(instance);
449-
assertEquals(OrchestrationRuntimeStatus.FAILED, instance.getRuntimeStatus());
450-
451-
FailureDetails details = instance.getFailureDetails();
452-
assertNotNull(details);
453-
assertTrue(details.getErrorMessage().contains(failureMessage));
454-
455-
// Rewind the failed orchestration
456-
client.rewindInstance(instanceId, "Rewinding sub-orchestration with failed activity");
457-
458-
// Wait for the orchestration to complete after rewind
459-
instance = client.waitForInstanceCompletion(instanceId, defaultTimeout, true);
460-
assertNotNull(instance);
461-
assertEquals(OrchestrationRuntimeStatus.COMPLETED, instance.getRuntimeStatus());
462-
assertEquals(expectedOutput, instance.readOutputAs(String.class));
463-
}
464-
}
465-
466416
@Test
467417
void continueAsNew() throws TimeoutException {
468418
final String orchestratorName = "continueAsNew";
@@ -655,107 +605,6 @@ void terminateSuspendOrchestration() throws TimeoutException, InterruptedExcepti
655605
}
656606
}
657607

658-
private void rewindFailedOrchestrationHelper(String rewindReason) throws TimeoutException {
659-
final String orchestratorName = "RewindOrchestration" + (rewindReason == null ? "NoReason" : "");
660-
final String activityName = "FailOnceActivity" + (rewindReason == null ? "NoReason" : "");
661-
final String expectedOutput = "Success after rewind" + (rewindReason == null ? " without reason" : "");
662-
final AtomicBoolean shouldFail = new AtomicBoolean(true);
663-
664-
DurableTaskGrpcWorker worker = this.createWorkerBuilder()
665-
.addOrchestrator(orchestratorName, ctx -> {
666-
String result = ctx.callActivity(activityName, null, String.class).await();
667-
ctx.complete(result);
668-
})
669-
.addActivity(activityName, ctx -> {
670-
if (shouldFail.compareAndSet(true, false)) {
671-
throw new RuntimeException("Simulated transient failure");
672-
}
673-
return expectedOutput;
674-
})
675-
.buildAndStart();
676-
677-
DurableTaskClient client = this.createClientBuilder().build();
678-
try (worker; client) {
679-
String instanceId = client.scheduleNewOrchestrationInstance(orchestratorName);
680-
681-
// Wait for the orchestration to fail
682-
OrchestrationMetadata instance = client.waitForInstanceCompletion(instanceId, defaultTimeout, false);
683-
assertNotNull(instance);
684-
assertEquals(OrchestrationRuntimeStatus.FAILED, instance.getRuntimeStatus());
685-
686-
// Rewind the failed orchestration
687-
if (rewindReason != null) {
688-
client.rewindInstance(instanceId, rewindReason);
689-
} else {
690-
client.rewindInstance(instanceId);
691-
}
692-
693-
// Wait for the orchestration to complete after rewind
694-
instance = client.waitForInstanceCompletion(instanceId, defaultTimeout, true);
695-
assertNotNull(instance);
696-
assertEquals(OrchestrationRuntimeStatus.COMPLETED, instance.getRuntimeStatus());
697-
assertEquals(expectedOutput, instance.readOutputAs(String.class));
698-
}
699-
}
700-
701-
@Test
702-
void rewindFailedOrchestration() throws TimeoutException {
703-
rewindFailedOrchestrationHelper("Rewinding after transient failure");
704-
}
705-
706-
@Test
707-
void rewindFailedOrchestrationWithoutReason() throws TimeoutException {
708-
rewindFailedOrchestrationHelper(null);
709-
}
710-
711-
@Test
712-
void rewindCompletedOrchestrationThrowsException() throws TimeoutException {
713-
final String orchestratorName = "RewindCompletedOrchestration";
714-
715-
DurableTaskGrpcWorker worker = this.createWorkerBuilder()
716-
.addOrchestrator(orchestratorName, ctx -> {
717-
ctx.complete("Completed successfully");
718-
})
719-
.buildAndStart();
720-
721-
DurableTaskClient client = this.createClientBuilder().build();
722-
try (worker; client) {
723-
String instanceId = client.scheduleNewOrchestrationInstance(orchestratorName);
724-
725-
// Wait for the orchestration to complete
726-
OrchestrationMetadata instance = client.waitForInstanceCompletion(instanceId, defaultTimeout, true);
727-
assertNotNull(instance);
728-
assertEquals(OrchestrationRuntimeStatus.COMPLETED, instance.getRuntimeStatus());
729-
730-
// Attempt to rewind a completed orchestration - should throw or be a no-op
731-
// Based on API behavior, rewind is only valid for FAILED orchestrations
732-
assertThrows(
733-
Exception.class,
734-
() -> client.rewindInstance(instanceId, "Attempting to rewind completed orchestration"),
735-
"Rewinding a completed orchestration should throw an exception"
736-
);
737-
}
738-
}
739-
740-
@Test
741-
void rewindNonExistentOrchestrationThrowsException() {
742-
final String orchestratorName = "RewindNonExistent";
743-
final String nonExistentId = "non-existent-instance-id";
744-
745-
DurableTaskGrpcWorker worker = this.createWorkerBuilder()
746-
.addOrchestrator(orchestratorName, ctx -> ctx.complete("done"))
747-
.buildAndStart();
748-
749-
DurableTaskClient client = this.createClientBuilder().build();
750-
try (worker; client) {
751-
assertThrows(
752-
Exception.class,
753-
() -> client.rewindInstance(nonExistentId, "Attempting to rewind non-existent orchestration"),
754-
"Rewinding a non-existent orchestration should throw an exception"
755-
);
756-
}
757-
}
758-
759608
@Test
760609
void activityFanOut() throws IOException, TimeoutException {
761610
final String orchestratorName = "ActivityFanOut";

samples/src/main/java/io/durabletask/samples/RewindPattern.java

Lines changed: 0 additions & 131 deletions
This file was deleted.

0 commit comments

Comments
 (0)