From 3831f3a266ba1cf08066aa00aac2e1e688a655c7 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 9 Mar 2026 08:33:48 +0000 Subject: [PATCH] fix: clear customStatus on continue-as-new in InMemoryOrchestrationBackend When an orchestration calls continueAsNew, the InMemoryOrchestrationBackend resets most instance state (history, input, output, failureDetails, status) but omits customStatus. This causes stale custom status values to persist across continue-as-new iterations, leading to incorrect test results when the new iteration does not explicitly set a custom status. The fix adds the missing reset of customStatus to undefined in the continue-as-new handling of processCompleteOrchestrationAction(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/testing/in-memory-backend.ts | 1 + .../test/in-memory-backend.spec.ts | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/packages/durabletask-js/src/testing/in-memory-backend.ts b/packages/durabletask-js/src/testing/in-memory-backend.ts index 4d88923e..2c96acb1 100644 --- a/packages/durabletask-js/src/testing/in-memory-backend.ts +++ b/packages/durabletask-js/src/testing/in-memory-backend.ts @@ -481,6 +481,7 @@ export class InMemoryOrchestrationBackend { instance.history = []; instance.input = newInput; instance.output = undefined; + instance.customStatus = undefined; instance.failureDetails = undefined; instance.status = pb.OrchestrationStatus.ORCHESTRATION_STATUS_PENDING; diff --git a/packages/durabletask-js/test/in-memory-backend.spec.ts b/packages/durabletask-js/test/in-memory-backend.spec.ts index 502e6961..66fe6a96 100644 --- a/packages/durabletask-js/test/in-memory-backend.spec.ts +++ b/packages/durabletask-js/test/in-memory-backend.spec.ts @@ -229,6 +229,32 @@ describe("In-Memory Backend", () => { expect(state?.serializedOutput).toEqual(JSON.stringify(5)); }); + it("should clear customStatus after continue-as-new", async () => { + const orchestrator: TOrchestrator = async (ctx: OrchestrationContext, input: number) => { + if (input === 1) { + // First iteration: set a custom status then continue-as-new + ctx.setCustomStatus("iteration-1-status"); + ctx.continueAsNew(2, false); + } else { + // Second iteration: do NOT set custom status — it should be cleared + return "done"; + } + }; + + worker.addOrchestrator(orchestrator); + await worker.start(); + + const id = await client.scheduleNewOrchestration(orchestrator, 1); + const state = await client.waitForOrchestrationCompletion(id, true, 10); + + expect(state).toBeDefined(); + expect(state?.runtimeStatus).toEqual(OrchestrationStatus.COMPLETED); + expect(state?.serializedOutput).toEqual(JSON.stringify("done")); + // customStatus must be cleared after continue-as-new when the new iteration + // does not set one — it should not carry over from the previous iteration + expect(state?.serializedCustomStatus).toBeUndefined(); + }); + it("should preserve sendEvent actions when continuing-as-new", async () => { // Receiver orchestration that waits for an event const receiver: TOrchestrator = async function* (ctx: OrchestrationContext): any {