diff --git a/packages/aws-durable-execution-sdk-js-examples/ADDING_EXAMPLES.md b/packages/aws-durable-execution-sdk-js-examples/ADDING_EXAMPLES.md index e935db18..50ff30dd 100644 --- a/packages/aws-durable-execution-sdk-js-examples/ADDING_EXAMPLES.md +++ b/packages/aws-durable-execution-sdk-js-examples/ADDING_EXAMPLES.md @@ -87,21 +87,20 @@ Create a test file in the same directory: ```typescript import { handler } from "./{example-name}"; -import { createTests } from "../../shared/test-helper"; // For nested: "../../../shared/test-helper" +import { createTests } from "../../../utils/test-helper"; // For standalone: "../../utils/test-helper" createTests({ - name: "my-example test", - functionName: "{example-name}", handler, - tests: (runner) => { - it("should return expected result", async () => { + tests: (runner, { assertEventSignatures }) => { + it("should execute successfully with expected result and operations", async () => { const execution = await runner.run(); - expect(execution.getResult()).toEqual("example result"); - }); - it("should execute correct number of operations", async () => { - const execution = await runner.run(); + // Multiple assertions on the same execution + expect(execution.getResult()).toEqual("example result"); expect(execution.getOperations()).toHaveLength(2); // adjust based on your example + + // REQUIRED: Must call assertEventSignatures for every test + assertEventSignatures(execution); }); }, }); @@ -172,38 +171,147 @@ The `createTests` helper provides a unified interface: ```typescript createTests({ - name: string; // Test suite name - functionName: string; // Must match handler filename (without .ts) - handler: Function; // The handler function to test - invocationType?: string; // Optional: 'RequestResponse' | 'Event' - tests: (runner, isCloud) => void; // Test definitions + handler: DurableLambdaHandler; // The handler function to test + tests: TestCallback; // Test definitions + invocationType?: InvocationType; // Optional: 'RequestResponse' | 'Event' + localRunnerConfig?: LocalDurableTestRunnerSetupParameters; // Optional local test config }); ``` Inside `tests`, you have access to: - `runner`: Either `LocalDurableTestRunner` or `CloudDurableTestRunner` -- `isCloud`: Boolean indicating if running against real Lambda +- `testHelper`: Object containing: + - `assertEventSignatures`: **Required** function to validate execution history + - `isTimeSkipping`: Boolean indicating if time is being skipped in tests + - `isCloud`: Boolean indicating if running against real Lambda + - `functionNameMap`: Helper for resolving function names in tests + +## Event Signature Validation with `assertEventSignatures` + +**IMPORTANT**: Every test **MUST** call `assertEventSignatures(execution)` at the end. This validates that the execution produces the expected sequence of durable execution events. + +### How it Works + +1. **First Run**: When you first create a test, run it with `GENERATE_HISTORY=true` to create the history file: + + ```bash + GENERATE_HISTORY=true npm test + ``` + +2. **History File Creation**: This generates a `.history.json` file next to your test containing the expected event signatures. + +3. **Subsequent Runs**: Normal test runs compare the actual events against the stored history file. + +### Example Usage + +```typescript +createTests({ + handler, + tests: (runner, { assertEventSignatures }) => { + it("should complete workflow successfully", async () => { + const execution = await runner.run(); + + // Your test assertions + expect(execution.getResult()).toEqual("completed"); + expect(execution.getOperations()).toHaveLength(3); + + // REQUIRED: Validate event signatures + assertEventSignatures(execution); + }); + + it("should handle callback operations", async () => { + const callbackOp = runner.getOperation("my-callback"); + const executionPromise = runner.run(); + + await callbackOp.waitForData(); + await callbackOp.sendCallbackSuccess("result"); + + const execution = await executionPromise; + expect(execution.getResult()).toEqual("result"); + + // REQUIRED: Validate event signatures + assertEventSignatures(execution); + }); + }, +}); +``` + +### Multiple History Files + +For tests with multiple scenarios, you can create separate history files: + +```typescript +it("should handle success case", async () => { + const execution = await runner.run({ scenario: "success" }); + expect(execution.getResult()).toBe("success"); + + // Creates/uses example-name-success.history.json + assertEventSignatures(execution, "success"); +}); + +it("should handle failure case", async () => { + const execution = await runner.run({ scenario: "failure" }); + expect(execution.getError()).toBeDefined(); + + // Creates/uses example-name-failure.history.json + assertEventSignatures(execution, "failure"); +}); +``` ### Common Test Patterns ```typescript -tests: (runner, isCloud) => { - it("should return expected result", async () => { +tests: (runner, { assertEventSignatures, isCloud, isTimeSkipping }) => { + // Combine tests with identical setup (same runner.run() call) + it("should execute successfully with expected result and operations", async () => { const execution = await runner.run(); + + // Multiple assertions on the same execution expect(execution.getResult()).toEqual(expectedValue); - }); + expect(execution.getOperations()).toHaveLength(3); - it("should execute operations in order", async () => { - const execution = await runner.run(); + // Check operations in order const ops = execution.getOperations(); - expect(ops[0].name).toBe("step-1"); - expect(ops[1].name).toBe("step-2"); + expect(ops[0].getName()).toBe("step-1"); + expect(ops[1].getName()).toBe("step-2"); + + // REQUIRED + assertEventSignatures(execution); + }); + + // Separate test only when setup is different (different parameters, callbacks, etc.) + it("should handle callback operations", async () => { + const callbackOp = runner.getOperation("my-callback"); + const executionPromise = runner.run(); + + // Wait for callback to start + await callbackOp.waitForData(); + + // Send callback result + await callbackOp.sendCallbackSuccess("callback-result"); + + const execution = await executionPromise; + expect(execution.getResult()).toContain("callback-result"); + + // REQUIRED + assertEventSignatures(execution); }); - it("should execute correct number of operations", async () => { + // Environment-specific tests with different setups + it("should behave differently in cloud vs local", async () => { const execution = await runner.run(); - expect(execution.getOperations()).toHaveLength(3); + + if (isCloud) { + // Cloud-specific assertions + expect(execution.getInvocations().length).toBeGreaterThan(1); + } else { + // Local-specific assertions + expect(isTimeSkipping).toBe(true); + } + + // REQUIRED + assertEventSignatures(execution); }); }; ``` @@ -213,6 +321,9 @@ tests: (runner, isCloud) => { - [ ] Created example file in appropriate directory structure - [ ] Created test file in same directory - [ ] Used correct import paths for test-helper and types +- [ ] Added `assertEventSignatures` parameter to test callback +- [ ] Called `assertEventSignatures(execution)` in every test +- [ ] Generated history files with `GENERATE_HISTORY=true npm test` - [ ] Local tests pass (`npm test`) - [ ] Integration tests pass in CI/CD @@ -231,6 +342,31 @@ sam local execution history $DURABLE_EXECUTION_ARN ## Troubleshooting -**Test not found in integration run:** +### assertEventSignatures Issues + +**Error: "assertEventSignature was not called for test [name]"** + +- You forgot to call `assertEventSignatures(execution)` in one or more of your tests +- Make sure every `it()` test calls this function + +**Error: "History file [...].history.json does not exist"** + +- Run the test with `GENERATE_HISTORY=true npm test` to create the history file +- Make sure the file is committed to your repository + +**Error: Event signature mismatch** + +- The execution produced different events than expected +- If this is intentional (you changed the function), regenerate the history with `GENERATE_HISTORY=true npm test` +- If not intentional, check your function logic for unintended changes + +**TypeError: testResult.getHistoryEvents is not a function** + +- You're passing the wrong variable to `assertEventSignatures` +- Pass the `execution` result from `runner.run()`, not `execution.getResult()` + +### Test Setup Issues + +**Tests timing out:** -- Verify `functionName` in test matches the example name +- For local tests with time skipping disabled: make sure step retries are not longer than the timeout diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.history.json new file mode 100644 index 00000000..f45986a7 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.history.json @@ -0,0 +1,124 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "5f684cc3-8224-4742-88fb-2d8c5fee3b56", + "EventTimestamp": "2025-12-17T19:42:18.573Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "api-call-1", + "EventTimestamp": "2025-12-17T19:42:18.578Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjZkNzk1NjczLTlmNjEtNGZhMC05NzVmLTRjNjdjOWMzZGNlOCIsIm9wZXJhdGlvbklkIjoiYzRjYTQyMzhhMGI5MjM4MiIsInRva2VuIjoiOTQ3OTk0YzYtNTc4ZC00YTBiLWJlMTktYzIxZGI1YzE0OWFkIn0=", + "Timeout": 300, + "Input": {} + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "c81e728d9d4c2f63", + "Name": "api-call-2", + "EventTimestamp": "2025-12-17T19:42:18.579Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjZkNzk1NjczLTlmNjEtNGZhMC05NzVmLTRjNjdjOWMzZGNlOCIsIm9wZXJhdGlvbklkIjoiYzgxZTcyOGQ5ZDRjMmY2MyIsInRva2VuIjoiNTMzMjg1NzEtMzcxZS00MjRiLTlhMDMtYjcyMzJlZmQzMGYzIn0=", + "Timeout": 300, + "Input": {} + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 4, + "Id": "eccbc87e4b5ce2fe", + "Name": "api-call-3", + "EventTimestamp": "2025-12-17T19:42:18.581Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjZkNzk1NjczLTlmNjEtNGZhMC05NzVmLTRjNjdjOWMzZGNlOCIsIm9wZXJhdGlvbklkIjoiZWNjYmM4N2U0YjVjZTJmZSIsInRva2VuIjoiYTNjZWQwNGYtODVkOS00ZTViLWI1MzYtMTRiYTcyNmZhMjdiIn0=", + "Timeout": 300, + "Input": {} + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:18.633Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.573Z", + "EndTimestamp": "2025-12-17T19:42:18.633Z", + "Error": {}, + "RequestId": "8361eb6f-70a2-4b5e-b5b2-c54dd93e22e4" + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "c81e728d9d4c2f63", + "Name": "api-call-2", + "EventTimestamp": "2025-12-17T19:42:18.683Z", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"id\":2,\"data\":\"second\"}" + } + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 7, + "Id": "c4ca4238a0b92382", + "Name": "api-call-1", + "EventTimestamp": "2025-12-17T19:42:18.683Z", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"id\":1,\"data\":\"first\"}" + } + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 8, + "Id": "eccbc87e4b5ce2fe", + "Name": "api-call-3", + "EventTimestamp": "2025-12-17T19:42:18.683Z", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"id\":3,\"data\":\"third\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:18.684Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.683Z", + "EndTimestamp": "2025-12-17T19:42:18.684Z", + "Error": {}, + "RequestId": "17417beb-b668-4e83-b508-cc881039bde3" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "5f684cc3-8224-4742-88fb-2d8c5fee3b56", + "EventTimestamp": "2025-12-17T19:42:18.684Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"results\":[\"{\\\"id\\\":1,\\\"data\\\":\\\"first\\\"}\",\"{\\\"id\\\":2,\\\"data\\\":\\\"second\\\"}\",\"{\\\"id\\\":3,\\\"data\\\":\\\"third\\\"}\"],\"allCompleted\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.test.ts index 037a15f9..1a6b5bda 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/concurrent/create-callback-concurrent.test.ts @@ -9,7 +9,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle multiple concurrent callback operations", async () => { // Get all callback operations const callback1 = runner.getOperation("api-call-1"); @@ -25,22 +25,27 @@ createTests({ callback3.waitForData(WaitingOperationStatus.STARTED), ]); + // Wait a bit to ensure invocations complete (TODO: add a waitForInvocation to testing lib) + await new Promise((resolve) => setTimeout(resolve, 100)); + // Complete callbacks in different order const callbackResult2 = JSON.stringify({ id: 2, data: "second", }); - await callback2.sendCallbackSuccess(callbackResult2); const callbackResult1 = JSON.stringify({ id: 1, data: "first", }); - await callback1.sendCallbackSuccess(callbackResult1); const callbackResult3 = JSON.stringify({ id: 3, data: "third", }); - await callback3.sendCallbackSuccess(callbackResult3); + await Promise.all([ + callback2.sendCallbackSuccess(callbackResult2), + callback1.sendCallbackSuccess(callbackResult1), + callback3.sendCallbackSuccess(callbackResult3), + ]); const result = await executionPromise; @@ -57,6 +62,10 @@ createTests({ (op) => op.getType() === OperationType.CALLBACK, ), ).toBe(true); + + assertEventSignatures(result, undefined, { + invocationCompletedDifference: 2, + }); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.history.json new file mode 100644 index 00000000..75d07635 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.history.json @@ -0,0 +1,129 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "4b0ad8a5-470d-4f72-a33c-ff2dea55cd3c", + "EventTimestamp": "2025-12-17T19:42:15.347Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "fetch-data", + "EventTimestamp": "2025-12-17T19:42:15.351Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "Name": "fetch-data", + "EventTimestamp": "2025-12-17T19:42:15.351Z", + "StepSucceededDetails": { + "Result": { + "Payload": "{\"userId\":123,\"name\":\"John Doe\"}" + }, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 4, + "Id": "c81e728d9d4c2f63", + "Name": "process-user", + "EventTimestamp": "2025-12-17T19:42:15.353Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjI5NWYwNzljLTc3MTYtNDliYi1hOTc5LTNhMTg0ZWIzNThmYyIsIm9wZXJhdGlvbklkIjoiYzgxZTcyOGQ5ZDRjMmY2MyIsInRva2VuIjoiMWNjNzkxZDAtOGYxZi00YjAyLThhMWUtOGNhZjJkNDE4OWUzIn0=", + "Timeout": 300, + "Input": {} + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 5, + "Id": "eccbc87e4b5ce2fe", + "Name": "initial-wait", + "EventTimestamp": "2025-12-17T19:42:15.355Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:16.355Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:42:15.406Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:15.347Z", + "EndTimestamp": "2025-12-17T19:42:15.406Z", + "Error": {}, + "RequestId": "79284f42-e519-439c-807b-f053dca645c9" + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 7, + "Id": "c81e728d9d4c2f63", + "Name": "process-user", + "EventTimestamp": "2025-12-17T19:42:15.455Z", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"processed\":true,\"timestamp\":1766000535454}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 8, + "EventTimestamp": "2025-12-17T19:42:15.507Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:15.456Z", + "EndTimestamp": "2025-12-17T19:42:15.507Z", + "Error": {}, + "RequestId": "9826cb11-2fff-4fa6-aaa1-afd2946562cd" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 9, + "Id": "eccbc87e4b5ce2fe", + "Name": "initial-wait", + "EventTimestamp": "2025-12-17T19:42:16.356Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 10, + "EventTimestamp": "2025-12-17T19:42:16.357Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.356Z", + "EndTimestamp": "2025-12-17T19:42:16.357Z", + "Error": {}, + "RequestId": "ffa7f89e-dd40-46a7-93b1-b58e55ef60e5" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 11, + "Id": "4b0ad8a5-470d-4f72-a33c-ff2dea55cd3c", + "EventTimestamp": "2025-12-17T19:42:16.357Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"stepResult\":{\"userId\":123,\"name\":\"John Doe\"},\"callbackResult\":\"{\\\"processed\\\":true,\\\"timestamp\\\":1766000535454}\",\"completed\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.test.ts index f6e6d840..45f1a5a4 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/mixed-ops/create-callback-mixed-ops.test.ts @@ -9,7 +9,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle callback operations mixed with other operation types", async () => { const callbackOperation = runner.getOperation("process-user"); @@ -18,6 +18,9 @@ createTests({ // Wait for callback to start (other operations complete synchronously) await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + // Wait for invocation to complete + await new Promise((resolve) => setTimeout(resolve, 100)); + // Complete the callback const callbackResult = JSON.stringify({ processed: true, @@ -41,6 +44,8 @@ createTests({ expect(operationTypes).toContain(OperationType.WAIT); expect(operationTypes).toContain(OperationType.STEP); expect(operationTypes).toContain(OperationType.CALLBACK); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure-undefined.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure-undefined.history.json new file mode 100644 index 00000000..8e079fc4 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure-undefined.history.json @@ -0,0 +1,77 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "05982c21-fb2d-4c87-a697-680894fea58f", + "EventTimestamp": "2025-12-17T19:42:18.967Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.969Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImJjZjNhN2I3LTEwZjItNGIyMS1iOTViLTAzZmVjNjQ5NzcwMyIsIm9wZXJhdGlvbklkIjoiYzRjYTQyMzhhMGI5MjM4MiIsInRva2VuIjoiY2ZlMDVhYmUtYjM1Zi00ZTFjLTk2Y2QtMmNlMmQ4OGFmOTFiIn0=", + "Input": {} + } + }, + { + "EventType": "CallbackFailed", + "SubType": "Callback", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.970Z", + "CallbackFailedDetails": { + "Error": { + "Payload": {} + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 4, + "EventTimestamp": "2025-12-17T19:42:19.021Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.967Z", + "EndTimestamp": "2025-12-17T19:42:19.021Z", + "Error": {}, + "RequestId": "f89a9546-fdfe-4ba2-811b-0792090d12fc" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:19.023Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:19.022Z", + "EndTimestamp": "2025-12-17T19:42:19.023Z", + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "Callback failed" + } + }, + "RequestId": "f84fe9e2-fbf1-4c12-a9f1-67b8d18a0669" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 6, + "Id": "05982c21-fb2d-4c87-a697-680894fea58f", + "EventTimestamp": "2025-12-17T19:42:19.023Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "Callback failed" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure.history.json new file mode 100644 index 00000000..658118bf --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-failure.history.json @@ -0,0 +1,79 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "35140fe0-045a-45dd-adfc-c1cb5da66f3c", + "EventTimestamp": "2025-12-17T19:42:18.646Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.649Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjZlZTZlYzZiLTk0MmMtNDMwYy04MzU0LTM0ZmEzYWZjNjVmZCIsIm9wZXJhdGlvbklkIjoiYzRjYTQyMzhhMGI5MjM4MiIsInRva2VuIjoiM2RkMTczZjMtYmYzZS00NjJiLTgxMmYtYWYwNGUwNDk0M2RiIn0=", + "Input": {} + } + }, + { + "EventType": "CallbackFailed", + "SubType": "Callback", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.649Z", + "CallbackFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "ERROR" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 4, + "EventTimestamp": "2025-12-17T19:42:18.701Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.646Z", + "EndTimestamp": "2025-12-17T19:42:18.701Z", + "Error": {}, + "RequestId": "0ca767e6-c865-4b4a-acf8-50a345756f02" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:18.703Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.702Z", + "EndTimestamp": "2025-12-17T19:42:18.703Z", + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "ERROR" + } + }, + "RequestId": "bb689b89-afff-4ee0-800a-6382971bc79c" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 6, + "Id": "35140fe0-045a-45dd-adfc-c1cb5da66f3c", + "EventTimestamp": "2025-12-17T19:42:18.703Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "ERROR" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success-undefined.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success-undefined.history.json new file mode 100644 index 00000000..defe9d12 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success-undefined.history.json @@ -0,0 +1,63 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "2f39c1c4-463a-4160-b6ac-6f23706dd8b6", + "EventTimestamp": "2025-12-17T19:42:18.805Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.808Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImJkMzg1YTJjLTYxZTgtNGM0Ni05OGNjLWFjNDU2YTJjMWY4ZSIsIm9wZXJhdGlvbklkIjoiYzRjYTQyMzhhMGI5MjM4MiIsInRva2VuIjoiMjYwOTQ4ODktMTg0NC00YTY0LWE3OGUtYjc3MDExNzA1NGFmIn0=", + "Input": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.809Z", + "CallbackSucceededDetails": { + "Result": {} + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 4, + "EventTimestamp": "2025-12-17T19:42:18.859Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.805Z", + "EndTimestamp": "2025-12-17T19:42:18.859Z", + "Error": {}, + "RequestId": "69c81a09-696d-465a-88fe-69edf557375e" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:18.862Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.861Z", + "EndTimestamp": "2025-12-17T19:42:18.862Z", + "Error": {}, + "RequestId": "a1167dc4-63fe-492e-afe4-f63716f65bdf" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 6, + "Id": "2f39c1c4-463a-4160-b6ac-6f23706dd8b6", + "EventTimestamp": "2025-12-17T19:42:18.862Z", + "ExecutionSucceededDetails": {} + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success.history.json new file mode 100644 index 00000000..15a816cf --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback-success.history.json @@ -0,0 +1,69 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "d61718c0-25c3-4a76-a3a5-ad0de0e0e04c", + "EventTimestamp": "2025-12-17T19:42:18.485Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.490Z", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjdlMWU0NzQxLTY1OGEtNDJhOS1iYjE4LWU1YmMxNGE3NGM5OSIsIm9wZXJhdGlvbklkIjoiYzRjYTQyMzhhMGI5MjM4MiIsInRva2VuIjoiZDlhNTU3N2ItMWFkMC00OTYyLWI2NDctOGM0MmVlMWQ2YjBjIn0=", + "Input": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:18.492Z", + "CallbackSucceededDetails": { + "Result": { + "Payload": "successful" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 4, + "EventTimestamp": "2025-12-17T19:42:18.541Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.485Z", + "EndTimestamp": "2025-12-17T19:42:18.541Z", + "Error": {}, + "RequestId": "c87cbc21-aebf-400a-a38c-36dcd807b6a1" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:18.543Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:18.542Z", + "EndTimestamp": "2025-12-17T19:42:18.543Z", + "Error": {}, + "RequestId": "e0381bc3-3cde-4625-af0f-1f14184d4229" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 6, + "Id": "d61718c0-25c3-4a76-a3a5-ad0de0e0e04c", + "EventTimestamp": "2025-12-17T19:42:18.543Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "\"successful\"" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback.test.ts index 82b26e44..68b86f16 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/create-callback/simple/create-callback.test.ts @@ -8,7 +8,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("function completes when callback succeeds - happy case", async () => { const res = "successful"; const executionPromise = runner.run(); @@ -21,6 +21,8 @@ createTests({ expect(callbackOp.getCallbackDetails()?.result).toStrictEqual(res); expect(execution.getResult()).toStrictEqual(res); + + assertEventSignatures(execution, "success"); }); it("function completes when callback fails - happy case", async () => { @@ -34,6 +36,8 @@ createTests({ expect(callbackOp.getCallbackDetails()?.error).toBeDefined(); expect(execution.getError()).toBeDefined(); + + assertEventSignatures(execution, "failure"); }); it("function completes when callback succeeds with undefined - edge case", async () => { @@ -48,6 +52,8 @@ createTests({ expect(callbackOp.getCallbackDetails()?.result).toBeUndefined(); expect(callbackOp.getCallbackDetails()?.error).toBeUndefined(); expect(execution.getResult()).toBeUndefined(); + + assertEventSignatures(execution, "success-undefined"); }); it("function completes when callback fails with undefined error message - edge case", async () => { @@ -67,6 +73,8 @@ createTests({ stackTrace: undefined, }); expect(execution.getError()).toBeDefined(); + + assertEventSignatures(execution, "failure-undefined"); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-basic-wait.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-basic-wait.history.json new file mode 100644 index 00000000..f0684fc3 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-basic-wait.history.json @@ -0,0 +1,72 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "e567fc4e-1af2-4ec6-8f22-e68cf0e4bb68", + "EventTimestamp": "2025-12-17T19:42:04.204Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"functionName\":\"wait-named\"}" + } + } + }, + { + "EventType": "ChainedInvokeStarted", + "SubType": "ChainedInvoke", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:04.206Z", + "ChainedInvokeStartedDetails": { + "FunctionName": "", + "Input": { + "Payload": "" + }, + "DurableExecutionArn": "" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:04.256Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:04.204Z", + "EndTimestamp": "2025-12-17T19:42:04.256Z", + "Error": {}, + "RequestId": "98ed8a54-c98e-46a5-856f-721423a1d4fc" + } + }, + { + "EventType": "ChainedInvokeSucceeded", + "SubType": "ChainedInvoke", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.323Z", + "ChainedInvokeSucceededDetails": { + "Result": { + "Payload": "\"wait finished\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:06.326Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.325Z", + "EndTimestamp": "2025-12-17T19:42:06.326Z", + "Error": {}, + "RequestId": "54f10185-dc1d-495b-8e0b-6ca7519b1f5b" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 6, + "Id": "e567fc4e-1af2-4ec6-8f22-e68cf0e4bb68", + "EventTimestamp": "2025-12-17T19:42:06.326Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "\"wait finished\"" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-child-failure.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-child-failure.history.json new file mode 100644 index 00000000..8b807388 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-child-failure.history.json @@ -0,0 +1,83 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "e97d214f-2098-4b6e-88d7-815817b1b85f", + "EventTimestamp": "2025-12-17T19:42:06.644Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"functionName\":\"handler-error\"}" + } + } + }, + { + "EventType": "ChainedInvokeStarted", + "SubType": "ChainedInvoke", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.647Z", + "ChainedInvokeStartedDetails": { + "FunctionName": "", + "Input": { + "Payload": "" + }, + "DurableExecutionArn": "" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:06.699Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.644Z", + "EndTimestamp": "2025-12-17T19:42:06.699Z", + "Error": {}, + "RequestId": "90502e6f-451a-4787-94a3-2c314d95e4e8" + } + }, + { + "EventType": "ChainedInvokeFailed", + "SubType": "ChainedInvoke", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.750Z", + "ChainedInvokeFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Intentional handler failure", + "ErrorType": "Error" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:06.757Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.757Z", + "EndTimestamp": "2025-12-17T19:42:06.757Z", + "Error": { + "Payload": { + "ErrorType": "InvokeError", + "ErrorMessage": "Intentional handler failure" + } + }, + "RequestId": "3da81e1d-9deb-4584-bfbb-559f89c7a9f6" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 6, + "Id": "e97d214f-2098-4b6e-88d7-815817b1b85f", + "EventTimestamp": "2025-12-17T19:42:06.758Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "InvokeError", + "ErrorMessage": "Intentional handler failure" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-failure.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-failure.history.json new file mode 100644 index 00000000..30c8ef6c --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-failure.history.json @@ -0,0 +1,84 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "90bfd695-7575-4b50-b87f-ad2455ebf96f", + "EventTimestamp": "2025-12-17T19:42:07.968Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"functionName\":\"non-durable\",\"payload\":{\"failure\":true}}" + } + } + }, + { + "EventType": "ChainedInvokeStarted", + "SubType": "ChainedInvoke", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:07.972Z", + "ChainedInvokeStartedDetails": { + "FunctionName": "", + "Input": { + "Payload": "" + }, + "DurableExecutionArn": "" + } + }, + { + "EventType": "ChainedInvokeFailed", + "SubType": "ChainedInvoke", + "EventId": 3, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:07.997Z", + "ChainedInvokeFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "This is a failure", + "ErrorType": "Error", + "StackTrace": ["Error: This is a failure", " at handler"] + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 4, + "EventTimestamp": "2025-12-17T19:42:08.022Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:07.968Z", + "EndTimestamp": "2025-12-17T19:42:08.022Z", + "Error": {}, + "RequestId": "f6075c5d-32c0-402d-a026-c5e831bdf07c" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:08.023Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.022Z", + "EndTimestamp": "2025-12-17T19:42:08.023Z", + "Error": { + "Payload": { + "ErrorType": "InvokeError", + "ErrorMessage": "This is a failure" + } + }, + "RequestId": "8f599618-031c-4d5b-926e-0c408e48d70d" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 6, + "Id": "90bfd695-7575-4b50-b87f-ad2455ebf96f", + "EventTimestamp": "2025-12-17T19:42:08.023Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "InvokeError", + "ErrorMessage": "This is a failure" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-success.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-success.history.json new file mode 100644 index 00000000..d019e686 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-non-durable-success.history.json @@ -0,0 +1,72 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "06930aef-2bab-4d30-b849-6342a12c3c11", + "EventTimestamp": "2025-12-17T19:42:06.859Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"functionName\":\"non-durable\"}" + } + } + }, + { + "EventType": "ChainedInvokeStarted", + "SubType": "ChainedInvoke", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.862Z", + "ChainedInvokeStartedDetails": { + "FunctionName": "", + "Input": { + "Payload": "" + }, + "DurableExecutionArn": "" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:06.914Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.859Z", + "EndTimestamp": "2025-12-17T19:42:06.914Z", + "Error": {}, + "RequestId": "5e933f78-6e30-4c74-b152-ded53f068eb4" + } + }, + { + "EventType": "ChainedInvokeSucceeded", + "SubType": "ChainedInvoke", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:07.863Z", + "ChainedInvokeSucceededDetails": { + "Result": { + "Payload": "{\"status\":200,\"body\":\"{\\\"message\\\":\\\"Hello from Lambda!\\\"}\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:07.866Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:07.865Z", + "EndTimestamp": "2025-12-17T19:42:07.866Z", + "Error": {}, + "RequestId": "1652dd6e-320f-4df4-81d6-f3854e7ff1c4" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 6, + "Id": "06930aef-2bab-4d30-b849-6342a12c3c11", + "EventTimestamp": "2025-12-17T19:42:07.866Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"status\":200,\"body\":\"{\\\"message\\\":\\\"Hello from Lambda!\\\"}\"}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-step-payload.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-step-payload.history.json new file mode 100644 index 00000000..15715616 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple-step-payload.history.json @@ -0,0 +1,72 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "0a7e7379-b91d-41ad-90d6-0f8c396e0fcc", + "EventTimestamp": "2025-12-17T19:42:06.431Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"functionName\":\"step-named\",\"payload\":{\"data\":\"data from parent\"}}" + } + } + }, + { + "EventType": "ChainedInvokeStarted", + "SubType": "ChainedInvoke", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.435Z", + "ChainedInvokeStartedDetails": { + "FunctionName": "", + "Input": { + "Payload": "" + }, + "DurableExecutionArn": "" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:06.486Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.431Z", + "EndTimestamp": "2025-12-17T19:42:06.486Z", + "Error": {}, + "RequestId": "3973e975-c9d8-4cf2-a1fc-2f1d4738a55f" + } + }, + { + "EventType": "ChainedInvokeSucceeded", + "SubType": "ChainedInvoke", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:06.541Z", + "ChainedInvokeSucceededDetails": { + "Result": { + "Payload": "\"processed: data from parent\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 5, + "EventTimestamp": "2025-12-17T19:42:06.542Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.541Z", + "EndTimestamp": "2025-12-17T19:42:06.542Z", + "Error": {}, + "RequestId": "77c10144-eb86-4e22-9b6e-e949fbbd1724" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 6, + "Id": "0a7e7379-b91d-41ad-90d6-0f8c396e0fcc", + "EventTimestamp": "2025-12-17T19:42:06.542Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "\"processed: data from parent\"" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple.test.ts index bcae854b..983c6ac7 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/invoke/simple/invoke-simple.test.ts @@ -8,7 +8,7 @@ import { handler as namedStepHandler } from "../../step/named/step-named"; createTests({ handler, - tests: function (runner, { functionNameMap }) { + tests: function (runner, { functionNameMap, assertEventSignatures }) { it("should run invoke with basic wait state", async () => { if (runner instanceof LocalDurableTestRunner) { runner.registerDurableFunction( @@ -23,6 +23,8 @@ createTests({ }, }); expect(result.getResult()).toBe("wait finished"); + + assertEventSignatures(result, "basic-wait"); }); it("should run invoke with step and payload", async () => { @@ -42,6 +44,8 @@ createTests({ }, }); expect(result.getResult()).toEqual("processed: data from parent"); + + assertEventSignatures(result, "step-payload"); }); it("should run invoke with child function failure", async () => { @@ -61,6 +65,8 @@ createTests({ errorMessage: "Intentional handler failure", errorType: "InvokeError", }); + + assertEventSignatures(result, "child-failure"); }); it("should run invoke with non-durable function success", async () => { @@ -82,6 +88,8 @@ createTests({ message: "Hello from Lambda!", }), }); + + assertEventSignatures(result, "non-durable-success"); }); it("should run invoke with non-durable function failure", async () => { @@ -104,6 +112,8 @@ createTests({ errorMessage: "This is a failure", errorType: "InvokeError", }); + + assertEventSignatures(result, "non-durable-failure"); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.history.json new file mode 100644 index 00000000..8d5753f9 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.history.json @@ -0,0 +1,473 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "6b4b8c57-a04f-4f93-af72-58903b2031d4", + "EventTimestamp": "2025-12-17T19:41:56.448Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "Map", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-items", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ContextStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "MapIteration", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "Name": "map-item-0", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "2f221a18eb863803", + "Name": "process-0", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "MapIteration", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "Name": "map-item-1", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 6, + "Id": "6151f5ab282d90e4", + "Name": "process-1", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "MapIteration", + "EventId": 7, + "Id": "13cee27a2bd93915", + "Name": "map-item-2", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 8, + "Id": "b425e0c75591aa8f", + "Name": "process-2", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "MapIteration", + "EventId": 9, + "Id": "3a170a9fe4f47efa", + "Name": "map-item-3", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "a4e1cd317d54f087", + "Name": "process-3", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "3a170a9fe4f47efa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "MapIteration", + "EventId": 11, + "Id": "12426c956d1bc501", + "Name": "map-item-4", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 12, + "Id": "0f42756e5788f9b0", + "Name": "process-4", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "12426c956d1bc501", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 13, + "Id": "2f221a18eb863803", + "Name": "process-0", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 3, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 14, + "Id": "6151f5ab282d90e4", + "Name": "process-1", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 4, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 15, + "Id": "b425e0c75591aa8f", + "Name": "process-2", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 3, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 16, + "Id": "a4e1cd317d54f087", + "Name": "process-3", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "3a170a9fe4f47efa", + "StepSucceededDetails": { + "Result": { + "Payload": "8" + }, + "RetryDetails": {} + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 17, + "Id": "0f42756e5788f9b0", + "Name": "process-4", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "12426c956d1bc501", + "StepSucceededDetails": { + "Result": { + "Payload": "10" + }, + "RetryDetails": {} + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "MapIteration", + "EventId": 18, + "Id": "3a170a9fe4f47efa", + "Name": "map-item-3", + "EventTimestamp": "2025-12-17T19:41:56.457Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "8" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "MapIteration", + "EventId": 19, + "Id": "12426c956d1bc501", + "Name": "map-item-4", + "EventTimestamp": "2025-12-17T19:41:56.457Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "10" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 20, + "EventTimestamp": "2025-12-17T19:41:56.507Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.448Z", + "EndTimestamp": "2025-12-17T19:41:56.507Z", + "Error": {}, + "RequestId": "d23a6e70-1827-4ad9-a28d-a0d96f555484" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 21, + "Id": "2f221a18eb863803", + "Name": "process-0", + "EventTimestamp": "2025-12-17T19:41:59.458Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 22, + "Id": "b425e0c75591aa8f", + "Name": "process-2", + "EventTimestamp": "2025-12-17T19:41:59.458Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 23, + "Id": "2f221a18eb863803", + "Name": "process-0", + "EventTimestamp": "2025-12-17T19:41:59.458Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 24, + "Id": "b425e0c75591aa8f", + "Name": "process-2", + "EventTimestamp": "2025-12-17T19:41:59.459Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "MapIteration", + "EventId": 25, + "Id": "ea66c06c1e1c05fa", + "Name": "map-item-0", + "EventTimestamp": "2025-12-17T19:41:59.461Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Item 1 failed" + } + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "MapIteration", + "EventId": 26, + "Id": "13cee27a2bd93915", + "Name": "map-item-2", + "EventTimestamp": "2025-12-17T19:41:59.461Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Item 3 failed" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 27, + "EventTimestamp": "2025-12-17T19:41:59.509Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:59.455Z", + "EndTimestamp": "2025-12-17T19:41:59.509Z", + "Error": {}, + "RequestId": "02a29da8-d8f2-488e-9564-d9c7ac74b3d1" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 28, + "Id": "6151f5ab282d90e4", + "Name": "process-1", + "EventTimestamp": "2025-12-17T19:42:00.458Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 29, + "Id": "6151f5ab282d90e4", + "Name": "process-1", + "EventTimestamp": "2025-12-17T19:42:00.458Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Item 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "MapIteration", + "EventId": 30, + "Id": "98c6f2c2287f4c73", + "Name": "map-item-1", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Item 2 failed" + } + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "Map", + "EventId": 31, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-items", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"all\":[{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":0,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":1,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":2,\"status\":\"FAILED\"},{\"result\":8,\"index\":3,\"status\":\"SUCCEEDED\"},{\"result\":10,\"index\":4,\"status\":\"SUCCEEDED\"}],\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\"}" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 32, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:01.460Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 33, + "EventTimestamp": "2025-12-17T19:42:00.510Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:00.455Z", + "EndTimestamp": "2025-12-17T19:42:00.510Z", + "Error": {}, + "RequestId": "1b09cfe6-8a5a-4a1e-8a5e-30b5ea004d07" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 34, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:01.460Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 35, + "EventTimestamp": "2025-12-17T19:42:01.461Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:01.460Z", + "EndTimestamp": "2025-12-17T19:42:01.461Z", + "Error": {}, + "RequestId": "a243840d-f679-41b9-bc88-c45bf45f2e96" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 36, + "Id": "6b4b8c57-a04f-4f93-af72-58903b2031d4", + "EventTimestamp": "2025-12-17T19:42:01.461Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\",\"successCount\":2,\"failureCount\":3,\"totalCount\":5}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.test.ts index dfa0b183..069f10c4 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/map/failure-threshold-exceeded-percentage/map-failure-threshold-exceeded-percentage.test.ts @@ -4,7 +4,7 @@ import { OperationStatus } from "@aws/durable-execution-sdk-js-testing"; createTests({ handler, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should return FAILURE_TOLERANCE_EXCEEDED when failure percentage exceeds threshold", async () => { const execution = await runner.run(); const result = execution.getResult() as any; @@ -24,6 +24,10 @@ createTests({ ].forEach(({ name, status }) => { expect(runner.getOperation(name)?.getStatus()).toBe(status); }); + + assertEventSignatures(execution, undefined, { + invocationCompletedDifference: 1, + }); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/basic/parallel-basic.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/basic/parallel-basic.test.ts index c4fc3e60..5c65cf0e 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/basic/parallel-basic.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/basic/parallel-basic.test.ts @@ -4,20 +4,15 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, tests: (runner, { assertEventSignatures }) => { - it("should run correct number of durable steps", async () => { - const execution = await runner.run(); - - expect(runner.getOperation("parallel").getChildOperations()).toHaveLength( - 3, - ); - }); - it("should return correct result", async () => { const execution = await runner.run(); const result = execution.getResult(); expect(execution.getResult()).toBeDefined(); + expect(runner.getOperation("parallel").getChildOperations()).toHaveLength( + 3, + ); assertEventSignatures(execution); }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.history.json new file mode 100644 index 00000000..c67d187d --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.history.json @@ -0,0 +1,462 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "ba4b1924-ced4-406c-b3a7-70efaf0a3336", + "EventTimestamp": "2025-12-17T19:41:56.446Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "Parallel", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-tasks", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ContextStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "Name": "parallel-branch-0", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "Name": "parallel-branch-1", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 6, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 7, + "Id": "13cee27a2bd93915", + "Name": "parallel-branch-2", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 8, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 9, + "Id": "3a170a9fe4f47efa", + "Name": "parallel-branch-3", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "a4e1cd317d54f087", + "Name": "task-4", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "3a170a9fe4f47efa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 11, + "Id": "12426c956d1bc501", + "Name": "parallel-branch-4", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 12, + "Id": "0f42756e5788f9b0", + "Name": "task-5", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "12426c956d1bc501", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 13, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 4, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 14, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 4, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 15, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 4, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 16, + "Id": "a4e1cd317d54f087", + "Name": "task-4", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "3a170a9fe4f47efa", + "StepSucceededDetails": { + "Result": { + "Payload": "\"Task 4 success\"" + }, + "RetryDetails": {} + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 17, + "Id": "0f42756e5788f9b0", + "Name": "task-5", + "EventTimestamp": "2025-12-17T19:41:56.452Z", + "ParentId": "12426c956d1bc501", + "StepSucceededDetails": { + "Result": { + "Payload": "\"Task 5 success\"" + }, + "RetryDetails": {} + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "ParallelBranch", + "EventId": 18, + "Id": "3a170a9fe4f47efa", + "Name": "parallel-branch-3", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"Task 4 success\"" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "ParallelBranch", + "EventId": 19, + "Id": "12426c956d1bc501", + "Name": "parallel-branch-4", + "EventTimestamp": "2025-12-17T19:41:56.454Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"Task 5 success\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 20, + "EventTimestamp": "2025-12-17T19:41:56.505Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.446Z", + "EndTimestamp": "2025-12-17T19:41:56.505Z", + "Error": {}, + "RequestId": "cee643e4-f397-4e9f-b378-4788b942ebcf" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 21, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 22, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 23, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 24, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 25, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 26, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:00.456Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 27, + "Id": "ea66c06c1e1c05fa", + "Name": "parallel-branch-0", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 1 failed" + } + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 28, + "Id": "98c6f2c2287f4c73", + "Name": "parallel-branch-1", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 2 failed" + } + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 29, + "Id": "13cee27a2bd93915", + "Name": "parallel-branch-2", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 3 failed" + } + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "Parallel", + "EventId": 30, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-tasks", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"all\":[{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":0,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":1,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":2,\"status\":\"FAILED\"},{\"result\":\"Task 4 success\",\"index\":3,\"status\":\"SUCCEEDED\"},{\"result\":\"Task 5 success\",\"index\":4,\"status\":\"SUCCEEDED\"}],\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\"}" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 31, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:00.459Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:01.459Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 32, + "EventTimestamp": "2025-12-17T19:42:00.510Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:00.453Z", + "EndTimestamp": "2025-12-17T19:42:00.510Z", + "Error": {}, + "RequestId": "be4f6361-4983-40ca-9f44-0716f053ee45" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 33, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:01.459Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 34, + "EventTimestamp": "2025-12-17T19:42:01.461Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:01.459Z", + "EndTimestamp": "2025-12-17T19:42:01.461Z", + "Error": {}, + "RequestId": "ef103e4a-0f3a-4e24-ab2f-960f91d96b90" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 35, + "Id": "ba4b1924-ced4-406c-b3a7-70efaf0a3336", + "EventTimestamp": "2025-12-17T19:42:01.461Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\",\"successCount\":2,\"failureCount\":3,\"totalCount\":5}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.test.ts index e90a380f..9e04ebf8 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-count/parallel-failure-threshold-exceeded-count.test.ts @@ -3,7 +3,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should return FAILURE_TOLERANCE_EXCEEDED when failure count exceeds threshold", async () => { const execution = await runner.run(); const result = execution.getResult() as any; @@ -12,6 +12,10 @@ createTests({ expect(result.successCount).toBe(2); // Tasks 4 and 5 succeed expect(result.failureCount).toBe(3); // Tasks 1, 2, 3 fail (exceeds threshold of 2) expect(result.totalCount).toBe(5); + + assertEventSignatures(execution, undefined, { + invocationCompletedDifference: 2, + }); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.history.json new file mode 100644 index 00000000..df585644 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.history.json @@ -0,0 +1,473 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "66c27018-dc2d-486a-8979-ac4560884907", + "EventTimestamp": "2025-12-17T19:42:02.000Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "Parallel", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-tasks", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ContextStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "Name": "parallel-branch-0", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "Name": "parallel-branch-1", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 6, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 7, + "Id": "13cee27a2bd93915", + "Name": "parallel-branch-2", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 8, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 9, + "Id": "3a170a9fe4f47efa", + "Name": "parallel-branch-3", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "a4e1cd317d54f087", + "Name": "task-4", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "3a170a9fe4f47efa", + "StepStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "ParallelBranch", + "EventId": 11, + "Id": "12426c956d1bc501", + "Name": "parallel-branch-4", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "c4ca4238a0b92382", + "ContextStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 12, + "Id": "0f42756e5788f9b0", + "Name": "task-5", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "12426c956d1bc501", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 13, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 2, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 14, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 15, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 16, + "Id": "a4e1cd317d54f087", + "Name": "task-4", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "3a170a9fe4f47efa", + "StepSucceededDetails": { + "Result": { + "Payload": "\"Task 4 success\"" + }, + "RetryDetails": {} + } + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 17, + "Id": "0f42756e5788f9b0", + "Name": "task-5", + "EventTimestamp": "2025-12-17T19:42:02.008Z", + "ParentId": "12426c956d1bc501", + "StepSucceededDetails": { + "Result": { + "Payload": "\"Task 5 success\"" + }, + "RetryDetails": {} + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "ParallelBranch", + "EventId": 18, + "Id": "3a170a9fe4f47efa", + "Name": "parallel-branch-3", + "EventTimestamp": "2025-12-17T19:42:02.011Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"Task 4 success\"" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "ParallelBranch", + "EventId": 19, + "Id": "12426c956d1bc501", + "Name": "parallel-branch-4", + "EventTimestamp": "2025-12-17T19:42:02.012Z", + "ParentId": "c4ca4238a0b92382", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"Task 5 success\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 20, + "EventTimestamp": "2025-12-17T19:42:02.060Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:02.000Z", + "EndTimestamp": "2025-12-17T19:42:02.060Z", + "Error": {}, + "RequestId": "d219fe04-3776-473a-9285-a3bdc52f37c4" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 21, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:03.013Z", + "ParentId": "98c6f2c2287f4c73", + "StepStartedDetails": {} + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 22, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:03.013Z", + "ParentId": "13cee27a2bd93915", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 23, + "Id": "6151f5ab282d90e4", + "Name": "task-2", + "EventTimestamp": "2025-12-17T19:42:03.013Z", + "ParentId": "98c6f2c2287f4c73", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 2 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 24, + "Id": "b425e0c75591aa8f", + "Name": "task-3", + "EventTimestamp": "2025-12-17T19:42:03.013Z", + "ParentId": "13cee27a2bd93915", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 3 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 25, + "Id": "98c6f2c2287f4c73", + "Name": "parallel-branch-1", + "EventTimestamp": "2025-12-17T19:42:03.016Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 2 failed" + } + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 26, + "Id": "13cee27a2bd93915", + "Name": "parallel-branch-2", + "EventTimestamp": "2025-12-17T19:42:03.016Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 3 failed" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 27, + "EventTimestamp": "2025-12-17T19:42:03.064Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:03.010Z", + "EndTimestamp": "2025-12-17T19:42:03.064Z", + "Error": {}, + "RequestId": "4807de26-6cb6-4ca7-9e3f-8f7b843700e4" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 28, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:04.010Z", + "ParentId": "ea66c06c1e1c05fa", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 29, + "Id": "2f221a18eb863803", + "Name": "task-1", + "EventTimestamp": "2025-12-17T19:42:04.010Z", + "ParentId": "ea66c06c1e1c05fa", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Task 1 failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "ParallelBranch", + "EventId": 30, + "Id": "ea66c06c1e1c05fa", + "Name": "parallel-branch-0", + "EventTimestamp": "2025-12-17T19:42:04.012Z", + "ParentId": "c4ca4238a0b92382", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Task 1 failed" + } + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "Parallel", + "EventId": 31, + "Id": "c4ca4238a0b92382", + "Name": "failure-threshold-tasks", + "EventTimestamp": "2025-12-17T19:42:04.012Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"all\":[{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":0,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":1,\"status\":\"FAILED\"},{\"error\":{\"cause\":{\"cause\":{\"name\":\"StepError\"},\"name\":\"StepError\",\"errorType\":\"StepError\"},\"name\":\"ChildContextError\",\"errorType\":\"ChildContextError\"},\"index\":2,\"status\":\"FAILED\"},{\"result\":\"Task 4 success\",\"index\":3,\"status\":\"SUCCEEDED\"},{\"result\":\"Task 5 success\",\"index\":4,\"status\":\"SUCCEEDED\"}],\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\"}" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 32, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:04.012Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:05.012Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 33, + "EventTimestamp": "2025-12-17T19:42:04.064Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:04.009Z", + "EndTimestamp": "2025-12-17T19:42:04.064Z", + "Error": {}, + "RequestId": "9dce9be2-765e-4cc1-845a-5f0f1f3d7b97" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 34, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:05.012Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 35, + "EventTimestamp": "2025-12-17T19:42:05.013Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:05.012Z", + "EndTimestamp": "2025-12-17T19:42:05.013Z", + "Error": {}, + "RequestId": "9db007d0-7dd6-4651-9338-c7cb76da1f22" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 36, + "Id": "66c27018-dc2d-486a-8979-ac4560884907", + "EventTimestamp": "2025-12-17T19:42:05.013Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"completionReason\":\"FAILURE_TOLERANCE_EXCEEDED\",\"successCount\":2,\"failureCount\":3,\"totalCount\":5}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.test.ts index 4bf35aa1..ec45c8b3 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/failure-threshold-exceeded-percentage/parallel-failure-threshold-exceeded-percentage.test.ts @@ -3,7 +3,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should return FAILURE_TOLERANCE_EXCEEDED when failure percentage exceeds threshold", async () => { const execution = await runner.run(); const result = execution.getResult() as any; @@ -12,6 +12,10 @@ createTests({ expect(result.successCount).toBe(2); // Tasks 4 and 5 succeed expect(result.failureCount).toBe(3); // Tasks 1, 2, 3 fail (60% > 50% threshold) expect(result.totalCount).toBe(5); + + assertEventSignatures(execution, undefined, { + invocationCompletedDifference: 1, + }); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/wait/parallel-wait.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/wait/parallel-wait.test.ts index b8bc1585..ad6fec0f 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/wait/parallel-wait.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/parallel/wait/parallel-wait.test.ts @@ -26,12 +26,7 @@ createTests({ expect(wait2SecondsOp.getWaitDetails()!.waitSeconds!).toBe(2); expect(wait5SecondsOp.getWaitDetails()!.waitSeconds!).toBe(5); - // Not compatible with latest changes applied. - // There is a good change that this issue is related to - // testing library handling PENDING items in a different way than - // backend. Backend only cound them after LAn SDK received the changes - // in checkpoint response. - // assertEventSignatures(execution); + assertEventSignatures(execution); }, 10000); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.history.json new file mode 100644 index 00000000..dc244ce1 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.history.json @@ -0,0 +1,112 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "1094a219-81fe-43e8-8a75-11e397abb61c", + "EventTimestamp": "2025-12-17T19:42:16.855Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:16.870Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:16.870Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjFjMzhjZjM2LTU4MGUtNDVjNC1iNDE5LWI1NWE2YzZhMDZjOSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiNWNkMDVkYjYtNThjZS00ZThhLThmMzktZDZkZDU3Y2MwYjQ3In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:16.874Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:17.873Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:17.875Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"data\":\"callback_completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:17.925Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.855Z", + "EndTimestamp": "2025-12-17T19:42:17.925Z", + "Error": {}, + "RequestId": "6173466a-d9cc-412a-9f11-4e2b685d12d1" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:17.929Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"data\\\":\\\"callback_completed\\\"}\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:17.929Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:17.927Z", + "EndTimestamp": "2025-12-17T19:42:17.929Z", + "Error": {}, + "RequestId": "a6ca13b5-04d9-4713-a3f0-445cab62e44e" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "1094a219-81fe-43e8-8a75-11e397abb61c", + "EventTimestamp": "2025-12-17T19:42:17.929Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"callbackResult\":\"{\\\"data\\\":\\\"callback_completed\\\"}\",\"completed\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.test.ts index 7367155f..e0bae396 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/anonymous/wait-for-callback-anonymous.test.ts @@ -8,15 +8,15 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle basic waitForCallback with anonymous submitter", async () => { // Start the execution (this will pause at the callback) const executionPromise = runner.run(); - const callbackOperation = runner.getOperationByIndex(1); + const callbackOperation = runner.getOperationByIndex(0); // Wait for the operation to be available - await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + await callbackOperation.waitForData(WaitingOperationStatus.SUBMITTED); const callbackResult = JSON.stringify({ data: "callback_completed", }); @@ -33,6 +33,8 @@ createTests({ // Verify operations were tracked expect(result.getOperations().length).toBeGreaterThan(0); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-failure.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-failure.history.json new file mode 100644 index 00000000..d2c0671e --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-failure.history.json @@ -0,0 +1,128 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "b29c0037-6842-4f4d-8b97-d534daa34de1", + "EventTimestamp": "2025-12-17T19:42:13.625Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:13.628Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:13.628Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjdkMmMyMWZmLTQyMTEtNDVmMy1iNmQ4LTE1MTNmYzE0MTE4YSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiYzQwOWVkYjYtNzU1MC00MjQ1LWFhMjAtNGZhZmIzMDQ5Nzg4In0=", + "Timeout": 5, + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.630Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.630Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackFailed", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:13.631Z", + "ParentId": "c4ca4238a0b92382", + "CallbackFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "ERROR" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:13.682Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:13.625Z", + "EndTimestamp": "2025-12-17T19:42:13.682Z", + "Error": {}, + "RequestId": "492e5147-318c-4445-8f41-391df01dc2b7" + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:13.686Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "ERROR" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:13.687Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:13.684Z", + "EndTimestamp": "2025-12-17T19:42:13.687Z", + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "ERROR" + } + }, + "RequestId": "77a2e2ac-427a-4fd3-a8fd-8aba1cb2a804" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 10, + "Id": "b29c0037-6842-4f4d-8b97-d534daa34de1", + "EventTimestamp": "2025-12-17T19:42:13.687Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "ERROR" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-success.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-success.history.json new file mode 100644 index 00000000..4cb65784 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-success.history.json @@ -0,0 +1,115 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "d85704a8-b3b7-4a45-b203-d10599649a30", + "EventTimestamp": "2025-12-17T19:42:13.458Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:13.463Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:13.463Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjdlMjVhYTExLTAzNjAtNDIyMS04ODMzLWE3N2YxODNhMDhhMSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiMjE5NWJhMTYtNWY4NS00M2E3LWE2MGMtM2M3NTE2YmVmMDhlIn0=", + "Timeout": 5, + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.465Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.465Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:13.466Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "succeeded" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:13.517Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:13.458Z", + "EndTimestamp": "2025-12-17T19:42:13.517Z", + "Error": {}, + "RequestId": "153d4d6d-b41e-4535-9e47-0df2dfc38e8e" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:13.521Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"succeeded\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:13.521Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:13.519Z", + "EndTimestamp": "2025-12-17T19:42:13.521Z", + "Error": {}, + "RequestId": "39fe6f96-c081-4352-8f22-364ea41a13f3" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "d85704a8-b3b7-4a45-b203-d10599649a30", + "EventTimestamp": "2025-12-17T19:42:13.521Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "\"succeeded\"" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-timed-out.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-timed-out.history.json new file mode 100644 index 00000000..59ea1c4e --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback-timed-out.history.json @@ -0,0 +1,128 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "7a6531fd-6cd8-4d3f-bb85-b14f4ee35b94", + "EventTimestamp": "2025-12-17T19:42:13.791Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"timeoutSeconds\":1}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:13.794Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:13.794Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImMwZjJiZTliLTU5NWQtNDMxNy1hZTlhLTlhNWYxNzk1NjRmNCIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiODgyNWQzZTItYWE3OS00N2IzLThmMGEtZjc2YmVjMmUxZDQ3In0=", + "Timeout": 1, + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.797Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:13.797Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:42:13.847Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:13.791Z", + "EndTimestamp": "2025-12-17T19:42:13.847Z", + "Error": {}, + "RequestId": "76a3a0a7-c0ee-4c7a-92f6-7ce0841c4e87" + } + }, + { + "EventType": "CallbackTimedOut", + "SubType": "Callback", + "EventId": 7, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:14.795Z", + "ParentId": "c4ca4238a0b92382", + "CallbackTimedOutDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Callback timed out" + } + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "my callback function", + "EventTimestamp": "2025-12-17T19:42:14.800Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "Callback timed out" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:14.801Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:14.797Z", + "EndTimestamp": "2025-12-17T19:42:14.801Z", + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "Callback timed out" + } + }, + "RequestId": "f0e28e2c-1000-4f8c-9587-7945a9fcec6a" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 10, + "Id": "7a6531fd-6cd8-4d3f-bb85-b14f4ee35b94", + "EventTimestamp": "2025-12-17T19:42:14.802Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "Callback timed out" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.test.ts index 41709a84..f6ba6e37 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.test.ts @@ -8,38 +8,45 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner, { isCloud }) => { + tests: (runner, { assertEventSignatures }) => { it("function completes when callback succeeds - happy case", async () => { const executionPromise = runner.run(); const waitForCallbackOp = runner.getOperationByIndex(0); - await waitForCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await waitForCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); await waitForCallbackOp.sendCallbackSuccess("succeeded"); const execution = await executionPromise; expect(execution.getResult()).toEqual("succeeded"); + + assertEventSignatures(execution, "success"); }); it("function completes when callback fails - happy case", async () => { const executionPromise = runner.run(); const waitForCallbackOp = runner.getOperationByIndex(0); - await waitForCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await waitForCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); await waitForCallbackOp.sendCallbackFailure({ ErrorMessage: "ERROR" }); const execution = await executionPromise; expect(execution.getError()).toBeDefined(); - }); - // TODO: fix testing lib local runner time scaling to handle timeouts better - if (isCloud) { - it("function times out when callback is not called - failure case", async () => { - const execution = await runner.run(); + assertEventSignatures(execution, "failure"); + }); - expect(execution.getError()).toBeDefined(); + it("function times out when callback is not called - failure case", async () => { + const execution = await runner.run({ + payload: { + timeoutSeconds: 1, + }, }); - } + + expect(execution.getError()).toBeDefined(); + + assertEventSignatures(execution, "timed-out"); + }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.ts index be305bd5..1a37cc28 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/basic/wait-for-callback.ts @@ -21,7 +21,7 @@ export const handler = withDurableExecution( "my callback function", mySubmitterFunction, { - timeout: { seconds: 5 }, + timeout: { seconds: event.timeoutSeconds ?? 5 }, }, ); log("Hello world after callback!"); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.history.json new file mode 100644 index 00000000..7eea90b6 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.history.json @@ -0,0 +1,253 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "8de3a045-bed6-404d-b826-33129c43b87a", + "EventTimestamp": "2025-12-17T19:42:15.251Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"test\":\"child-context-callbacks\"}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "parent-callback-op", + "EventTimestamp": "2025-12-17T19:42:15.258Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:15.258Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImIzYzYzYWU1LWJiMmMtNDQ2Ny04MDcyLWNlYjA1MDhiYjBmOSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiNWM1MDI0MDEtMmQwYi00ZGZhLWEyOTItMThjMzExOGRlMmE3In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:15.261Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:15.261Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:15.262Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"parentData\":\"parent-completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:15.312Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:15.251Z", + "EndTimestamp": "2025-12-17T19:42:15.312Z", + "Error": {}, + "RequestId": "eb7a0b7d-b7a9-4d0e-b0e7-d70d6a3e9407" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "parent-callback-op", + "EventTimestamp": "2025-12-17T19:42:15.316Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"parentData\\\":\\\"parent-completed\\\"}\"" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "RunInChildContext", + "EventId": 9, + "Id": "c81e728d9d4c2f63", + "Name": "child-context-with-callback", + "EventTimestamp": "2025-12-17T19:42:15.316Z", + "ContextStartedDetails": {} + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 10, + "Id": "8fbdbf5573b18fae", + "Name": "child-wait", + "EventTimestamp": "2025-12-17T19:42:15.316Z", + "ParentId": "c81e728d9d4c2f63", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:16.316Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 11, + "EventTimestamp": "2025-12-17T19:42:15.368Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:15.314Z", + "EndTimestamp": "2025-12-17T19:42:15.368Z", + "Error": {}, + "RequestId": "a88769fb-5dc7-4715-afb8-bcc38b46b16f" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 12, + "Id": "8fbdbf5573b18fae", + "Name": "child-wait", + "EventTimestamp": "2025-12-17T19:42:16.317Z", + "ParentId": "c81e728d9d4c2f63", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 13, + "Id": "3c46a0407be60a1f", + "Name": "child-callback-op", + "EventTimestamp": "2025-12-17T19:42:16.319Z", + "ParentId": "c81e728d9d4c2f63", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 14, + "Id": "61e70e07c25ca2dd", + "EventTimestamp": "2025-12-17T19:42:16.319Z", + "ParentId": "3c46a0407be60a1f", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImIzYzYzYWU1LWJiMmMtNDQ2Ny04MDcyLWNlYjA1MDhiYjBmOSIsIm9wZXJhdGlvbklkIjoiNjFlNzBlMDdjMjVjYTJkZCIsInRva2VuIjoiZmRiODcwYjUtNDkxYS00MDNhLWExMDQtYjE5MjZiNzU0YzVhIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 15, + "Id": "c2f098f784fd6490", + "EventTimestamp": "2025-12-17T19:42:16.320Z", + "ParentId": "3c46a0407be60a1f", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 16, + "Id": "c2f098f784fd6490", + "EventTimestamp": "2025-12-17T19:42:16.320Z", + "ParentId": "3c46a0407be60a1f", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 17, + "Id": "61e70e07c25ca2dd", + "EventTimestamp": "2025-12-17T19:42:16.321Z", + "ParentId": "3c46a0407be60a1f", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"childData\":42}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 18, + "EventTimestamp": "2025-12-17T19:42:16.371Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.317Z", + "EndTimestamp": "2025-12-17T19:42:16.371Z", + "Error": {}, + "RequestId": "7efe07d3-7840-413d-bd7b-7f90ace4136a" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 19, + "Id": "3c46a0407be60a1f", + "Name": "child-callback-op", + "EventTimestamp": "2025-12-17T19:42:16.375Z", + "ParentId": "c81e728d9d4c2f63", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"childData\\\":42}\"" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "RunInChildContext", + "EventId": 20, + "Id": "c81e728d9d4c2f63", + "Name": "child-context-with-callback", + "EventTimestamp": "2025-12-17T19:42:16.376Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"childResult\":\"{\\\"childData\\\":42}\",\"childProcessed\":true}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 21, + "EventTimestamp": "2025-12-17T19:42:16.378Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.373Z", + "EndTimestamp": "2025-12-17T19:42:16.378Z", + "Error": {}, + "RequestId": "cf03e004-7f68-4fe1-aca1-2dd70b441952" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 22, + "Id": "8de3a045-bed6-404d-b826-33129c43b87a", + "EventTimestamp": "2025-12-17T19:42:16.379Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"parentResult\":\"{\\\"parentData\\\":\\\"parent-completed\\\"}\",\"childContextResult\":{\"childResult\":\"{\\\"childData\\\":42}\",\"childProcessed\":true}}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.test.ts index 1ad3adaa..859f8f41 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/child-context/wait-for-callback-child-context.test.ts @@ -9,7 +9,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle waitForCallback within child contexts", async () => { // Get operations - parent callback, child context, child wait, child callback const parentCallbackOp = runner.getOperation("parent-callback-op"); @@ -21,15 +21,14 @@ createTests({ }); // Wait for parent callback to start - await parentCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await parentCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); const parentCallbackResult = JSON.stringify({ parentData: "parent-completed", }); - console.log("parent callback op", parentCallbackOp.getOperationData()); await parentCallbackOp.sendCallbackSuccess(parentCallbackResult); // Wait for child callback to start - await childCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await childCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); const childCallbackResult = JSON.stringify({ childData: 42 }); console.log("child callback op", childCallbackOp.getOperationData()); await childCallbackOp.sendCallbackSuccess(childCallbackResult); @@ -52,6 +51,8 @@ createTests({ status: OperationStatus.SUCCEEDED, }); expect(completedOperations.length).toBe(8); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.history.json new file mode 100644 index 00000000..621e3cf2 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.history.json @@ -0,0 +1,180 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "ad907c65-abd9-459f-bf03-4e720e5be19e", + "EventTimestamp": "2025-12-17T19:42:06.506Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "failing-submitter-callback", + "EventTimestamp": "2025-12-17T19:42:06.511Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:06.511Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6Ijk5OGM4YjRhLWYzZGMtNGYwNy1iZjY3LWY0Y2QzMjI5YjgzZSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiYWU2NDhjOWEtMzQxNy00ZWRiLTg3MjItNWU4NzAwZGNmMzBhIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:06.513Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:07.013Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:42:07.065Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:06.506Z", + "EndTimestamp": "2025-12-17T19:42:07.064Z", + "Error": {}, + "RequestId": "2fd371fc-c418-4236-bc4e-251ca4802a6f" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 7, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:08.019Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 8, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:08.521Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:08.572Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.016Z", + "EndTimestamp": "2025-12-17T19:42:08.572Z", + "Error": {}, + "RequestId": "1dfd9857-88a9-426c-a7c1-9473c2db29bc" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:09.524Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 11, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:10.025Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 2 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 12, + "Id": "c4ca4238a0b92382", + "Name": "failing-submitter-callback", + "EventTimestamp": "2025-12-17T19:42:10.027Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Submitter failed" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 13, + "EventTimestamp": "2025-12-17T19:42:10.028Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:09.522Z", + "EndTimestamp": "2025-12-17T19:42:10.028Z", + "Error": {}, + "RequestId": "380271db-75df-42b4-8b21-b15c39ffe371" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 14, + "Id": "ad907c65-abd9-459f-bf03-4e720e5be19e", + "EventTimestamp": "2025-12-17T19:42:10.028Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"success\":false,\"error\":\"Submitter failed\"}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.test.ts index 203b5d5c..9e87eb7f 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failing-submitter/wait-for-callback-failing-submitter.test.ts @@ -5,15 +5,16 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { - // Pending resolution of https://github.com/aws/aws-durable-execution-sdk-js/issues/199 - it.skip("should handle waitForCallback with failing submitter function errors", async () => { + tests: (runner, { assertEventSignatures }) => { + it("should handle waitForCallback with failing submitter function errors", async () => { const execution = await runner.run(); expect(execution.getResult()).toEqual({ success: false, error: "Submitter failed", }); + + assertEventSignatures(execution); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.history.json new file mode 100644 index 00000000..b3630b89 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.history.json @@ -0,0 +1,118 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "6da307a3-bc2a-4f76-9e4e-e19a3baecfe3", + "EventTimestamp": "2025-12-17T19:42:14.375Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:14.378Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:14.378Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjI0NGI0ZDU0LWYyNWMtNDQxNy1iNGQ5LTUxMDdjNDQ1MjU1ZiIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiOGNlOWM1YjctMWFlNS00MTAxLTgxNjktNWZjOWRmYzU5ZWQ0In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:14.379Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:15.381Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackFailed", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:15.383Z", + "ParentId": "c4ca4238a0b92382", + "CallbackFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "External API failure", + "ErrorType": "APIException" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:15.433Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:14.374Z", + "EndTimestamp": "2025-12-17T19:42:15.433Z", + "Error": {}, + "RequestId": "49512b4f-4a28-4ea4-a3e1-d5b99cfef51f" + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:15.435Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "CallbackError", + "ErrorMessage": "External API failure" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:15.435Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:15.434Z", + "EndTimestamp": "2025-12-17T19:42:15.435Z", + "Error": {}, + "RequestId": "b83c175b-9c12-4185-bcca-d1897e4e0af9" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "6da307a3-bc2a-4f76-9e4e-e19a3baecfe3", + "EventTimestamp": "2025-12-17T19:42:15.436Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"success\":false,\"error\":\"External API failure\"}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.test.ts index 7c1d87bd..f5fec204 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/failures/wait-for-callback-failures.test.ts @@ -8,15 +8,15 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle waitForCallback with callback failure scenarios", async () => { // Start the execution (this will pause at the callback) const executionPromise = runner.run(); - const callbackOperation = runner.getOperationByIndex(1); + const callbackOperation = runner.getOperationByIndex(0); // Wait for the operation to be available (submitter succeeded) - await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + await callbackOperation.waitForData(WaitingOperationStatus.SUBMITTED); // Simulate external system failing the callback await callbackOperation.sendCallbackFailure({ @@ -33,6 +33,8 @@ createTests({ const completedOperations = result.getOperations(); expect(completedOperations.length).toEqual(3); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.history.json new file mode 100644 index 00000000..b65a5622 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.history.json @@ -0,0 +1,113 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "24a12113-e0c5-49ba-9a1f-648f88d051a5", + "EventTimestamp": "2025-12-17T19:42:08.952Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"isCloud\":false}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:08.958Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:08.959Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6Ijg2ZjQ3ZGE5LTY0YTktNDg4MC05NTU4LTRhOGRlMTI5ZGU2YSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiMDEyZjMwMjgtMTRiMC00YjIyLTk5ZDEtZGUxODdiNzgyMTY3In0=", + "HeartbeatTimeout": 1, + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:08.961Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:09.063Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:42:09.114Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.952Z", + "EndTimestamp": "2025-12-17T19:42:09.114Z", + "Error": {}, + "RequestId": "c3811301-8648-456e-b452-ef34425adc2f" + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 7, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:09.666Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"processed\":1000}" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:09.679Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"processed\\\":1000}\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:09.688Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:09.668Z", + "EndTimestamp": "2025-12-17T19:42:09.688Z", + "Error": {}, + "RequestId": "0fbd0284-c2d2-43ea-b018-1dd68fa8ff18" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "24a12113-e0c5-49ba-9a1f-648f88d051a5", + "EventTimestamp": "2025-12-17T19:42:09.688Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"callbackResult\":\"{\\\"processed\\\":1000}\",\"completed\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.test.ts index a6fbceff..395deaa9 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/heartbeat-sends/wait-for-callback-heartbeat-sends.test.ts @@ -12,16 +12,16 @@ createTests({ localRunnerConfig: { skipTime: false, }, - tests: (runner, { isCloud }) => { + tests: (runner, { isCloud, assertEventSignatures }) => { it("should handle waitForCallback heartbeat scenarios during long-running submitter execution", async () => { const executionPromise = runner.run({ payload: { isCloud }, }); - const callbackOperation = runner.getOperationByIndex(1); + const callbackOperation = runner.getOperationByIndex(0); // Wait for the operation to be available - await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + await callbackOperation.waitForData(WaitingOperationStatus.SUBMITTED); // Send heartbeat to keep the callback alive during processing await callbackOperation.sendCallbackHeartbeat(); @@ -53,6 +53,8 @@ createTests({ status: OperationStatus.SUCCEEDED, }); expect(completedOperations.length).toBeGreaterThan(0); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.history.json new file mode 100644 index 00000000..3ebe6dd1 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.history.json @@ -0,0 +1,228 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "6400ea64-7038-4daa-8bfd-262376b86f78", + "EventTimestamp": "2025-12-17T19:42:07.267Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "initial-wait", + "EventTimestamp": "2025-12-17T19:42:07.272Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:08.272Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:07.324Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:07.267Z", + "EndTimestamp": "2025-12-17T19:42:07.324Z", + "Error": {}, + "RequestId": "0b010d5d-87fd-4708-af86-7b8f1593152b" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "Name": "initial-wait", + "EventTimestamp": "2025-12-17T19:42:08.272Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 5, + "Id": "c81e728d9d4c2f63", + "Name": "fetch-user-data", + "EventTimestamp": "2025-12-17T19:42:08.285Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 6, + "Id": "c81e728d9d4c2f63", + "Name": "fetch-user-data", + "EventTimestamp": "2025-12-17T19:42:08.285Z", + "StepSucceededDetails": { + "Result": { + "Payload": "{\"userId\":123,\"name\":\"John Doe\"}" + }, + "RetryDetails": {} + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 7, + "Id": "eccbc87e4b5ce2fe", + "Name": "wait-for-callback", + "EventTimestamp": "2025-12-17T19:42:08.289Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 8, + "Id": "c9e6e7b69f98f516", + "EventTimestamp": "2025-12-17T19:42:08.289Z", + "ParentId": "eccbc87e4b5ce2fe", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjA3Yjk5MGY1LTQyM2UtNDVhMi1hZjVkLTg1ZTgyNzcyNmE5ZiIsIm9wZXJhdGlvbklkIjoiYzllNmU3YjY5Zjk4ZjUxNiIsInRva2VuIjoiOTYyZjFjNWMtOTFlZS00MWIwLTkwMmYtYzc0NjM4NzdiZTA4In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 9, + "Id": "b772d43b49bb57b5", + "EventTimestamp": "2025-12-17T19:42:08.292Z", + "ParentId": "eccbc87e4b5ce2fe", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 10, + "Id": "b772d43b49bb57b5", + "EventTimestamp": "2025-12-17T19:42:08.392Z", + "ParentId": "eccbc87e4b5ce2fe", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 11, + "Id": "c9e6e7b69f98f516", + "EventTimestamp": "2025-12-17T19:42:08.393Z", + "ParentId": "eccbc87e4b5ce2fe", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"processed\":true}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 12, + "EventTimestamp": "2025-12-17T19:42:08.443Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.277Z", + "EndTimestamp": "2025-12-17T19:42:08.443Z", + "Error": {}, + "RequestId": "c544bf18-b1d1-4708-ba21-e6de1780a4ff" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 13, + "Id": "eccbc87e4b5ce2fe", + "Name": "wait-for-callback", + "EventTimestamp": "2025-12-17T19:42:08.447Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"processed\\\":true}\"" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 14, + "Id": "a87ff679a2f3e71d", + "Name": "final-wait", + "EventTimestamp": "2025-12-17T19:42:08.447Z", + "WaitStartedDetails": { + "Duration": 2, + "ScheduledEndTimestamp": "2025-12-17T19:42:10.447Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 15, + "EventTimestamp": "2025-12-17T19:42:08.498Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.445Z", + "EndTimestamp": "2025-12-17T19:42:08.498Z", + "Error": {}, + "RequestId": "3e4a0fc2-6814-4d40-90d2-3cf18ea7c093" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 16, + "Id": "a87ff679a2f3e71d", + "Name": "final-wait", + "EventTimestamp": "2025-12-17T19:42:10.449Z", + "WaitSucceededDetails": { + "Duration": 2 + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 17, + "Id": "e4da3b7fbbce2345", + "Name": "finalize-processing", + "EventTimestamp": "2025-12-17T19:42:10.451Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 18, + "Id": "e4da3b7fbbce2345", + "Name": "finalize-processing", + "EventTimestamp": "2025-12-17T19:42:10.451Z", + "StepSucceededDetails": { + "Result": { + "Payload": "{\"status\":\"completed\",\"timestamp\":1766000530450}" + }, + "RetryDetails": {} + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 19, + "EventTimestamp": "2025-12-17T19:42:10.451Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:10.449Z", + "EndTimestamp": "2025-12-17T19:42:10.451Z", + "Error": {}, + "RequestId": "9a61727c-fa83-4aee-9135-c9c56529526c" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 20, + "Id": "6400ea64-7038-4daa-8bfd-262376b86f78", + "EventTimestamp": "2025-12-17T19:42:10.451Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"stepResult\":{\"userId\":123,\"name\":\"John Doe\"},\"callbackResult\":\"{\\\"processed\\\":true}\",\"finalStep\":{\"status\":\"completed\",\"timestamp\":1766000530450},\"workflowCompleted\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.test.ts index aa070fab..fa2bbe7a 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/mixed-ops/wait-for-callback-mixed-ops.test.ts @@ -9,14 +9,14 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle waitForCallback mixed with steps, waits, and other operations", async () => { const callbackOperation = runner.getOperation("wait-for-callback"); const executionPromise = runner.run(); // Wait for callback to start (other operations complete synchronously with skipTime) - await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + await callbackOperation.waitForData(WaitingOperationStatus.SUBMITTED); // Complete the callback const callbackResult = JSON.stringify({ processed: true }); @@ -44,6 +44,8 @@ createTests({ status: OperationStatus.SUCCEEDED, }); expect(completedOperations.length).toBe(7); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.history.json new file mode 100644 index 00000000..84b5f093 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.history.json @@ -0,0 +1,284 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "35d4b60f-968c-4cc5-9eca-afba4744271a", + "EventTimestamp": "2025-12-17T19:42:10.438Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"test\":\"multiple-invocations\"}" + } + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "wait-invocation-1", + "EventTimestamp": "2025-12-17T19:42:10.442Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:11.442Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 3, + "EventTimestamp": "2025-12-17T19:42:10.494Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:10.438Z", + "EndTimestamp": "2025-12-17T19:42:10.494Z", + "Error": {}, + "RequestId": "9ac382f7-8550-4ad8-a141-43228e9ace45" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 4, + "Id": "c4ca4238a0b92382", + "Name": "wait-invocation-1", + "EventTimestamp": "2025-12-17T19:42:11.442Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 5, + "Id": "c81e728d9d4c2f63", + "Name": "first-callback", + "EventTimestamp": "2025-12-17T19:42:11.456Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 6, + "Id": "8fbdbf5573b18fae", + "EventTimestamp": "2025-12-17T19:42:11.456Z", + "ParentId": "c81e728d9d4c2f63", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjhmN2ZhMWQ4LTMwZmMtNGU0Ny05YjhkLWNkNGYwNDRiNDU5MCIsIm9wZXJhdGlvbklkIjoiOGZiZGJmNTU3M2IxOGZhZSIsInRva2VuIjoiOTNmZGNmZjktNDcwNy00M2IzLThjZGQtZDVlOGZiZWU4M2I4In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 7, + "Id": "3c46a0407be60a1f", + "EventTimestamp": "2025-12-17T19:42:11.458Z", + "ParentId": "c81e728d9d4c2f63", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 8, + "Id": "3c46a0407be60a1f", + "EventTimestamp": "2025-12-17T19:42:11.458Z", + "ParentId": "c81e728d9d4c2f63", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 9, + "Id": "8fbdbf5573b18fae", + "EventTimestamp": "2025-12-17T19:42:11.460Z", + "ParentId": "c81e728d9d4c2f63", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"step\":1}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 10, + "EventTimestamp": "2025-12-17T19:42:11.510Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:11.454Z", + "EndTimestamp": "2025-12-17T19:42:11.510Z", + "Error": {}, + "RequestId": "646ee3ea-3e59-4abd-9559-f74b28186284" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 11, + "Id": "c81e728d9d4c2f63", + "Name": "first-callback", + "EventTimestamp": "2025-12-17T19:42:11.517Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"step\\\":1}\"" + } + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 12, + "Id": "eccbc87e4b5ce2fe", + "Name": "process-callback-data", + "EventTimestamp": "2025-12-17T19:42:11.517Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 13, + "Id": "eccbc87e4b5ce2fe", + "Name": "process-callback-data", + "EventTimestamp": "2025-12-17T19:42:11.517Z", + "StepSucceededDetails": { + "Result": { + "Payload": "{\"processed\":true,\"step\":1}" + }, + "RetryDetails": {} + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 14, + "Id": "a87ff679a2f3e71d", + "Name": "wait-invocation-2", + "EventTimestamp": "2025-12-17T19:42:11.519Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:12.519Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 15, + "EventTimestamp": "2025-12-17T19:42:11.570Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:11.512Z", + "EndTimestamp": "2025-12-17T19:42:11.570Z", + "Error": {}, + "RequestId": "b4a8e3ea-90d4-43fa-a20e-84957a35efd6" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 16, + "Id": "a87ff679a2f3e71d", + "Name": "wait-invocation-2", + "EventTimestamp": "2025-12-17T19:42:12.519Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 17, + "Id": "e4da3b7fbbce2345", + "Name": "second-callback", + "EventTimestamp": "2025-12-17T19:42:12.521Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 18, + "Id": "19a1de167122a18a", + "EventTimestamp": "2025-12-17T19:42:12.521Z", + "ParentId": "e4da3b7fbbce2345", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjhmN2ZhMWQ4LTMwZmMtNGU0Ny05YjhkLWNkNGYwNDRiNDU5MCIsIm9wZXJhdGlvbklkIjoiMTlhMWRlMTY3MTIyYTE4YSIsInRva2VuIjoiZjAxODM0ZDMtMzczMC00Zjk1LTliNzYtN2NhMTllYzEzOTBkIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 19, + "Id": "dca19ffa163054fe", + "EventTimestamp": "2025-12-17T19:42:12.523Z", + "ParentId": "e4da3b7fbbce2345", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 20, + "Id": "dca19ffa163054fe", + "EventTimestamp": "2025-12-17T19:42:12.523Z", + "ParentId": "e4da3b7fbbce2345", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 21, + "Id": "19a1de167122a18a", + "EventTimestamp": "2025-12-17T19:42:12.524Z", + "ParentId": "e4da3b7fbbce2345", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"step\":2}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 22, + "EventTimestamp": "2025-12-17T19:42:12.575Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:12.519Z", + "EndTimestamp": "2025-12-17T19:42:12.575Z", + "Error": {}, + "RequestId": "08eda800-173a-4f7d-83ec-784609d07050" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 23, + "Id": "e4da3b7fbbce2345", + "Name": "second-callback", + "EventTimestamp": "2025-12-17T19:42:12.579Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"step\\\":2}\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 24, + "EventTimestamp": "2025-12-17T19:42:12.579Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:12.576Z", + "EndTimestamp": "2025-12-17T19:42:12.579Z", + "Error": {}, + "RequestId": "2aff428c-8844-4668-8957-fc22a108a2d1" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 25, + "Id": "35d4b60f-968c-4cc5-9eca-afba4744271a", + "EventTimestamp": "2025-12-17T19:42:12.579Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"firstCallback\":\"{\\\"step\\\":1}\",\"secondCallback\":\"{\\\"step\\\":2}\",\"stepResult\":{\"processed\":true,\"step\":1},\"invocationCount\":\"multiple\"}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.test.ts index 92e6bc4b..6b574b09 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/multiple-invocations/wait-for-callback-multiple-invocations.test.ts @@ -11,7 +11,7 @@ createTests({ localRunnerConfig: { skipTime: false, }, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle multiple invocations tracking with waitForCallback operations", async () => { // Get operations for verification const firstCallbackOp = runner.getOperation("first-callback"); @@ -51,6 +51,8 @@ createTests({ // Verify operations were executed const operations = result.getOperations(); expect(operations.length).toBeGreaterThan(4); // wait + callback + step + wait + callback operations + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.history.json new file mode 100644 index 00000000..7a71897e --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.history.json @@ -0,0 +1,358 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "c712c50e-4790-4009-b7e8-9dea2f0bea63", + "EventTimestamp": "2025-12-17T19:41:56.451Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "outer-callback-op", + "EventTimestamp": "2025-12-17T19:41:56.455Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:41:56.455Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6Ijc5MjU5ODY3LTBjOGUtNDIyOC1hZTcxLTIzZjU0ZWE5OWI4YyIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiM2RiNDY2NjYtNjkyYi00OTY5LWIzMjAtY2I5MGVmOWU1Mzk2In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.458Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.458Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:41:56.459Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"level\":\"outer-completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:41:56.509Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.450Z", + "EndTimestamp": "2025-12-17T19:41:56.508Z", + "Error": {}, + "RequestId": "c20dc73f-cb73-492a-9a43-9fba641eaec2" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "outer-callback-op", + "EventTimestamp": "2025-12-17T19:41:56.512Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"level\\\":\\\"outer-completed\\\"}\"" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "RunInChildContext", + "EventId": 9, + "Id": "c81e728d9d4c2f63", + "Name": "outer-child-context", + "EventTimestamp": "2025-12-17T19:41:56.512Z", + "ContextStartedDetails": {} + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 10, + "Id": "8fbdbf5573b18fae", + "Name": "inner-callback-op", + "EventTimestamp": "2025-12-17T19:41:56.512Z", + "ParentId": "c81e728d9d4c2f63", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 11, + "Id": "de9160b4a2cf6c27", + "EventTimestamp": "2025-12-17T19:41:56.512Z", + "ParentId": "8fbdbf5573b18fae", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6Ijc5MjU5ODY3LTBjOGUtNDIyOC1hZTcxLTIzZjU0ZWE5OWI4YyIsIm9wZXJhdGlvbklkIjoiZGU5MTYwYjRhMmNmNmMyNyIsInRva2VuIjoiNTYzYTQ3YjUtYTYzZC00ZWQxLTgyZGEtNGYzZjU0NTUyODRmIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 12, + "Id": "0d9f92bdd748d70d", + "EventTimestamp": "2025-12-17T19:41:56.513Z", + "ParentId": "8fbdbf5573b18fae", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 13, + "Id": "0d9f92bdd748d70d", + "EventTimestamp": "2025-12-17T19:41:56.513Z", + "ParentId": "8fbdbf5573b18fae", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 14, + "Id": "de9160b4a2cf6c27", + "EventTimestamp": "2025-12-17T19:41:56.514Z", + "ParentId": "8fbdbf5573b18fae", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"level\":\"inner-completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 15, + "EventTimestamp": "2025-12-17T19:41:56.567Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.510Z", + "EndTimestamp": "2025-12-17T19:41:56.566Z", + "Error": {}, + "RequestId": "d4013581-4e43-46b3-9bf1-b670fcd1288f" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 16, + "Id": "8fbdbf5573b18fae", + "Name": "inner-callback-op", + "EventTimestamp": "2025-12-17T19:41:56.571Z", + "ParentId": "c81e728d9d4c2f63", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"level\\\":\\\"inner-completed\\\"}\"" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "RunInChildContext", + "EventId": 17, + "Id": "3c46a0407be60a1f", + "Name": "inner-child-context", + "EventTimestamp": "2025-12-17T19:41:56.571Z", + "ParentId": "c81e728d9d4c2f63", + "ContextStartedDetails": {} + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 18, + "Id": "61e70e07c25ca2dd", + "Name": "deep-wait", + "EventTimestamp": "2025-12-17T19:41:56.573Z", + "ParentId": "3c46a0407be60a1f", + "WaitStartedDetails": { + "Duration": 5, + "ScheduledEndTimestamp": "2025-12-17T19:42:01.573Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 19, + "EventTimestamp": "2025-12-17T19:41:56.625Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.568Z", + "EndTimestamp": "2025-12-17T19:41:56.625Z", + "Error": {}, + "RequestId": "1128b8d1-f7e5-4a57-aa15-ecaaef95358d" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 20, + "Id": "61e70e07c25ca2dd", + "Name": "deep-wait", + "EventTimestamp": "2025-12-17T19:42:01.572Z", + "ParentId": "3c46a0407be60a1f", + "WaitSucceededDetails": { + "Duration": 5 + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 21, + "Id": "c2f098f784fd6490", + "Name": "nested-callback-op", + "EventTimestamp": "2025-12-17T19:42:01.575Z", + "ParentId": "3c46a0407be60a1f", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 22, + "Id": "1d03fc80da7b6145", + "EventTimestamp": "2025-12-17T19:42:01.575Z", + "ParentId": "c2f098f784fd6490", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6Ijc5MjU5ODY3LTBjOGUtNDIyOC1hZTcxLTIzZjU0ZWE5OWI4YyIsIm9wZXJhdGlvbklkIjoiMWQwM2ZjODBkYTdiNjE0NSIsInRva2VuIjoiMWNmNjcwZDEtYWIxMi00M2MxLWI4ZmQtODA2MzRjN2QxZGVlIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 23, + "Id": "8976069e5d6bb1a6", + "EventTimestamp": "2025-12-17T19:42:01.578Z", + "ParentId": "c2f098f784fd6490", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 24, + "Id": "8976069e5d6bb1a6", + "EventTimestamp": "2025-12-17T19:42:01.578Z", + "ParentId": "c2f098f784fd6490", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 25, + "Id": "1d03fc80da7b6145", + "EventTimestamp": "2025-12-17T19:42:01.579Z", + "ParentId": "c2f098f784fd6490", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"level\":\"nested-completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 26, + "EventTimestamp": "2025-12-17T19:42:01.630Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:01.572Z", + "EndTimestamp": "2025-12-17T19:42:01.630Z", + "Error": {}, + "RequestId": "556e6fd5-8602-439d-8ab5-bfa0c0e79e26" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 27, + "Id": "c2f098f784fd6490", + "Name": "nested-callback-op", + "EventTimestamp": "2025-12-17T19:42:01.634Z", + "ParentId": "3c46a0407be60a1f", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"level\\\":\\\"nested-completed\\\"}\"" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "RunInChildContext", + "EventId": 28, + "Id": "3c46a0407be60a1f", + "Name": "inner-child-context", + "EventTimestamp": "2025-12-17T19:42:01.634Z", + "ParentId": "c81e728d9d4c2f63", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"nestedCallback\":\"{\\\"level\\\":\\\"nested-completed\\\"}\",\"deepLevel\":\"inner-child\"}" + } + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "RunInChildContext", + "EventId": 29, + "Id": "c81e728d9d4c2f63", + "Name": "outer-child-context", + "EventTimestamp": "2025-12-17T19:42:01.634Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "{\"innerCallback\":\"{\\\"level\\\":\\\"inner-completed\\\"}\",\"deepNested\":{\"nestedCallback\":\"{\\\"level\\\":\\\"nested-completed\\\"}\",\"deepLevel\":\"inner-child\"},\"level\":\"outer-child\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 30, + "EventTimestamp": "2025-12-17T19:42:01.634Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:01.631Z", + "EndTimestamp": "2025-12-17T19:42:01.634Z", + "Error": {}, + "RequestId": "0282e82f-3a83-489b-a1ce-c9587bd85ebf" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 31, + "Id": "c712c50e-4790-4009-b7e8-9dea2f0bea63", + "EventTimestamp": "2025-12-17T19:42:01.634Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"outerCallback\":\"{\\\"level\\\":\\\"outer-completed\\\"}\",\"nestedResults\":{\"innerCallback\":\"{\\\"level\\\":\\\"inner-completed\\\"}\",\"deepNested\":{\"nestedCallback\":\"{\\\"level\\\":\\\"nested-completed\\\"}\",\"deepLevel\":\"inner-child\"},\"level\":\"outer-child\"}}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.test.ts index 32ce3fc2..16304c5a 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/nested/wait-for-callback-nested.test.ts @@ -8,7 +8,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle nested waitForCallback operations in child contexts", async () => { // Get operations - outer callback, outer context, inner callback, inner context, deep wait, nested callback const outerCallbackOp = runner.getOperation("outer-callback-op"); @@ -20,15 +20,15 @@ createTests({ const executionPromise = runner.run(); // Complete callbacks in sequence - await outerCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await outerCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); const outerCallbackResult = JSON.stringify({ level: "outer-completed" }); await outerCallbackOp.sendCallbackSuccess(outerCallbackResult); - await innerCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await innerCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); const innerCallbackResult = JSON.stringify({ level: "inner-completed" }); await innerCallbackOp.sendCallbackSuccess(innerCallbackResult); - await nestedCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await nestedCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); const nestedCallbackResult = JSON.stringify({ level: "nested-completed", }); @@ -58,6 +58,8 @@ createTests({ // Should have tracked all operations const completedOperations = result.getOperations(); expect(completedOperations.length).toBe(12); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.history.json new file mode 100644 index 00000000..817a5594 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.history.json @@ -0,0 +1,101 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "3cbab68f-20b1-4d91-8053-a66efa40d1b1", + "EventTimestamp": "2025-12-17T19:42:02.163Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:02.167Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:02.167Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjljOTVlOTRmLWViZGYtNDEwNi04MmRkLTgyZmJlMWVhZjM0MiIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiNDYzMGFkNmItNTNjNy00OGFjLTgwOWEtMjIwNjQ1YWQ2ODMxIn0=", + "Input": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 4, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:02.168Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{}" + } + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:02.170Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 6, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:02.170Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 7, + "Id": "c4ca4238a0b92382", + "EventTimestamp": "2025-12-17T19:42:02.172Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{}\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 8, + "EventTimestamp": "2025-12-17T19:42:02.172Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:02.163Z", + "EndTimestamp": "2025-12-17T19:42:02.172Z", + "Error": {}, + "RequestId": "0b6e708e-cc82-4d5f-8cb7-7abc424ef97b" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 9, + "Id": "3cbab68f-20b1-4d91-8053-a66efa40d1b1", + "EventTimestamp": "2025-12-17T19:42:02.172Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"callbackResult\":\"{}\",\"success\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.test.ts index 26775d42..3f0d596c 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/quick-completion/wait-for-callback-quick-completion.test.ts @@ -8,7 +8,7 @@ createTests({ localRunnerConfig: { skipTime: false, }, - tests: (runner, { isCloud }) => { + tests: (runner, { isCloud, assertEventSignatures }) => { it("should handle waitForCallback when callback completes before ", async () => { const callbackOp = runner.getOperationByIndex(0); @@ -32,6 +32,8 @@ createTests({ success: true, }); expect(result.getInvocations().length).toBe(1); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.history.json new file mode 100644 index 00000000..8b0ce649 --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.history.json @@ -0,0 +1,189 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "1786cba2-d720-468c-b378-5e163fffa680", + "EventTimestamp": "2025-12-17T19:42:16.876Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "custom-serdes-callback", + "EventTimestamp": "2025-12-17T19:42:16.884Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:16.884Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImY1YTA1ZjA1LTZlMjctNGJiNy05ZTQ5LTUzYzZlNmE2ODM1MSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiYzE4ZDEzZDAtM2Q3Ni00MjY5LTk2ODYtM2MxMjZlMmJkZjVlIn0=", + "Timeout": 300, + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:16.888Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:16.888Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:16.890Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"id\":42,\"message\":\"Hello Custom Serdes\",\"timestamp\":\"2025-06-15T12:30:45Z\",\"metadata\":{\"version\":\"2.0.0\",\"processed\":false}}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:42:16.941Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.876Z", + "EndTimestamp": "2025-12-17T19:42:16.941Z", + "Error": {}, + "RequestId": "2f5a1204-69be-4b97-a417-ee168632bae4" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "custom-serdes-callback", + "EventTimestamp": "2025-12-17T19:42:16.946Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"id\\\":42,\\\"message\\\":\\\"Hello Custom Serdes\\\",\\\"timestamp\\\":\\\"2025-06-15T12:30:45Z\\\",\\\"metadata\\\":{\\\"version\\\":\\\"2.0.0\\\",\\\"processed\\\":false}}\"" + } + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 9, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:16.946Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 10, + "Id": "c81e728d9d4c2f63", + "EventTimestamp": "2025-12-17T19:42:16.946Z", + "StepSucceededDetails": { + "Result": { + "Payload": "true" + }, + "RetryDetails": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 11, + "Id": "eccbc87e4b5ce2fe", + "EventTimestamp": "2025-12-17T19:42:16.948Z", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 12, + "Id": "eccbc87e4b5ce2fe", + "EventTimestamp": "2025-12-17T19:42:16.948Z", + "StepSucceededDetails": { + "Result": { + "Payload": "true" + }, + "RetryDetails": {} + } + }, + { + "EventType": "WaitStarted", + "SubType": "Wait", + "EventId": 13, + "Id": "a87ff679a2f3e71d", + "EventTimestamp": "2025-12-17T19:42:16.950Z", + "WaitStartedDetails": { + "Duration": 1, + "ScheduledEndTimestamp": "2025-12-17T19:42:17.950Z" + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 14, + "EventTimestamp": "2025-12-17T19:42:17.002Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:16.943Z", + "EndTimestamp": "2025-12-17T19:42:17.002Z", + "Error": {}, + "RequestId": "92cf6343-b084-4e51-a7c5-294a7f004a91" + } + }, + { + "EventType": "WaitSucceeded", + "SubType": "Wait", + "EventId": 15, + "Id": "a87ff679a2f3e71d", + "EventTimestamp": "2025-12-17T19:42:17.953Z", + "WaitSucceededDetails": { + "Duration": 1 + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 16, + "EventTimestamp": "2025-12-17T19:42:17.954Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:17.953Z", + "EndTimestamp": "2025-12-17T19:42:17.954Z", + "Error": {}, + "RequestId": "e78e423d-09cb-4466-a015-03358e9b54da" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 17, + "Id": "1786cba2-d720-468c-b378-5e163fffa680", + "EventTimestamp": "2025-12-17T19:42:17.954Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"receivedData\":{\"id\":42,\"message\":\"Hello Custom Serdes\",\"timestamp\":\"2025-06-15T12:30:45.000Z\",\"metadata\":{\"version\":\"2.0.0\",\"processed\":true}},\"hasCircularReference\":true,\"isDateAfterReplay\":true,\"isDateBeforeReplay\":true,\"isSerdesProcessedBefore\":true,\"isSerdesProcessedAfter\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.test.ts index 7102488b..a9c061ae 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/serdes/wait-for-callback-serdes.test.ts @@ -9,13 +9,13 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should handle waitForCallback with custom serdes configuration", async () => { const executionPromise = runner.run(); const callbackOperation = runner.getOperation("custom-serdes-callback"); - await callbackOperation.waitForData(WaitingOperationStatus.STARTED); + await callbackOperation.waitForData(WaitingOperationStatus.SUBMITTED); // Serialize the data using custom serdes for sending await callbackOperation.sendCallbackSuccess( @@ -60,6 +60,8 @@ createTests({ status: OperationStatus.SUCCEEDED, }); expect(completedOperations.length).toBeGreaterThan(0); + + assertEventSignatures(result); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.history.json new file mode 100644 index 00000000..c9d249db --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.history.json @@ -0,0 +1,180 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "a7cfa6f1-37c3-47c1-890d-be5b35522340", + "EventTimestamp": "2025-12-17T19:42:05.532Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "failing-submitter-callback", + "EventTimestamp": "2025-12-17T19:42:05.537Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:42:05.537Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjlmZmU0OGRiLTk1ZjUtNDVjNi1iMzAzLTQ3YzMzYzk5NmMwZSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiMWM4Nzg0ZmQtNTViOS00NWY0LThkNTctMWRhOTlmODI3YWY1In0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:05.539Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:06.039Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:42:06.090Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:05.532Z", + "EndTimestamp": "2025-12-17T19:42:06.090Z", + "Error": {}, + "RequestId": "ee32eee3-c5b8-4fbc-b659-19319642ffb4" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 7, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:07.043Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 8, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:07.544Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:42:07.595Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:07.041Z", + "EndTimestamp": "2025-12-17T19:42:07.595Z", + "Error": {}, + "RequestId": "0f5596ab-d80e-49ac-aad7-fd9cc9baba1b" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:08.547Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 11, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:09.047Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Submitter failed", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 2 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 12, + "Id": "c4ca4238a0b92382", + "Name": "failing-submitter-callback", + "EventTimestamp": "2025-12-17T19:42:09.050Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Submitter failed" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 13, + "EventTimestamp": "2025-12-17T19:42:09.050Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:08.545Z", + "EndTimestamp": "2025-12-17T19:42:09.050Z", + "Error": {}, + "RequestId": "1462c64e-fce6-46a2-b64f-0cbb6ba18c12" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 14, + "Id": "a7cfa6f1-37c3-47c1-890d-be5b35522340", + "EventTimestamp": "2025-12-17T19:42:09.050Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"success\":false,\"error\":\"Submitter failed\"}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.test.ts index f464d455..338a39b8 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-failure-catchable/wait-for-callback-submitter-failure-catchable.test.ts @@ -5,7 +5,7 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should catch submitter failure in try-catch block", async () => { const execution = await runner.run(); @@ -15,18 +15,8 @@ createTests({ success: false, error: expect.stringContaining("Submitter failed"), }); - }); - - it("should handle submitter failure gracefully after retries", async () => { - const execution = await runner.run(); - - // Verify error is caught and returned in response - const result = execution.getResult() as any; - expect(result.success).toBe(false); - expect(result.error).toContain("Submitter failed"); - // Execution completes successfully (doesn't hang or throw unhandled error) - expect(execution.getResult()).toBeDefined(); + assertEventSignatures(execution); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-failure.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-failure.history.json new file mode 100644 index 00000000..982611dd --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-failure.history.json @@ -0,0 +1,228 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "5730ea96-1cb6-4e34-a64c-fa7bfcdf09ff", + "EventTimestamp": "2025-12-17T19:41:56.626Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"shouldFail\":true}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "retry-submitter-callback", + "EventTimestamp": "2025-12-17T19:41:56.629Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:41:56.629Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6ImIwZGJiMzBjLWNjNjItNGIxNS04YTZiLWU0MjExMWZmMjRkMSIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiNTMwZmVlODUtZjM3ZC00OTliLThjY2QtYzAyNDlmMTFmMjgzIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.631Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.631Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Simulated submitter failure", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 1, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 6, + "EventTimestamp": "2025-12-17T19:41:56.682Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.626Z", + "EndTimestamp": "2025-12-17T19:41:56.682Z", + "Error": {}, + "RequestId": "e4010f99-7dc8-4d1d-8109-985b499b8e72" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 7, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:57.633Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 8, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:57.633Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Simulated submitter failure", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 2, + "CurrentAttempt": 1 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:41:57.685Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:57.631Z", + "EndTimestamp": "2025-12-17T19:41:57.685Z", + "Error": {}, + "RequestId": "7a0a6c56-b12d-4d88-912f-18b7b5f49218" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 10, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:59.636Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 11, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:59.636Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Simulated submitter failure", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "NextAttemptDelaySeconds": 4, + "CurrentAttempt": 2 + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 12, + "EventTimestamp": "2025-12-17T19:41:59.688Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:59.634Z", + "EndTimestamp": "2025-12-17T19:41:59.688Z", + "Error": {}, + "RequestId": "1b6a684a-3d35-4e50-a5e9-c75b343bf20e" + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 13, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:03.641Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepFailed", + "SubType": "Step", + "EventId": 14, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:42:03.641Z", + "ParentId": "c4ca4238a0b92382", + "StepFailedDetails": { + "Error": { + "Payload": { + "ErrorMessage": "Simulated submitter failure", + "ErrorType": "Error" + } + }, + "RetryDetails": { + "CurrentAttempt": 3 + } + } + }, + { + "EventType": "ContextFailed", + "SubType": "WaitForCallback", + "EventId": 15, + "Id": "c4ca4238a0b92382", + "Name": "retry-submitter-callback", + "EventTimestamp": "2025-12-17T19:42:03.644Z", + "ContextFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "StepError", + "ErrorMessage": "Simulated submitter failure" + } + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 16, + "EventTimestamp": "2025-12-17T19:42:03.644Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:42:03.637Z", + "EndTimestamp": "2025-12-17T19:42:03.644Z", + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "Simulated submitter failure" + } + }, + "RequestId": "e11d7b13-4403-4848-b530-c890830dd793" + } + }, + { + "EventType": "ExecutionFailed", + "EventId": 17, + "Id": "5730ea96-1cb6-4e34-a64c-fa7bfcdf09ff", + "EventTimestamp": "2025-12-17T19:42:03.645Z", + "ExecutionFailedDetails": { + "Error": { + "Payload": { + "ErrorType": "ChildContextError", + "ErrorMessage": "Simulated submitter failure" + } + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-success.history.json b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-success.history.json new file mode 100644 index 00000000..3055adbd --- /dev/null +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success-success.history.json @@ -0,0 +1,114 @@ +[ + { + "EventType": "ExecutionStarted", + "EventId": 1, + "Id": "537ac9c0-a15f-4546-9287-acd7f3cecc26", + "EventTimestamp": "2025-12-17T19:41:56.457Z", + "ExecutionStartedDetails": { + "Input": { + "Payload": "{\"shouldFail\":false}" + } + } + }, + { + "EventType": "ContextStarted", + "SubType": "WaitForCallback", + "EventId": 2, + "Id": "c4ca4238a0b92382", + "Name": "retry-submitter-callback", + "EventTimestamp": "2025-12-17T19:41:56.462Z", + "ContextStartedDetails": {} + }, + { + "EventType": "CallbackStarted", + "SubType": "Callback", + "EventId": 3, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:41:56.462Z", + "ParentId": "c4ca4238a0b92382", + "CallbackStartedDetails": { + "CallbackId": "eyJleGVjdXRpb25JZCI6IjA2ZmQwN2Q1LTY5YmUtNDNlNC1hMTJjLWEzYmMyMDk0NjcwMCIsIm9wZXJhdGlvbklkIjoiZWE2NmMwNmMxZTFjMDVmYSIsInRva2VuIjoiZGEwMWMxMjktMTgyOS00OGRjLWI2ODMtN2U1ZjE4OTM5MDljIn0=", + "Input": {} + } + }, + { + "EventType": "StepStarted", + "SubType": "Step", + "EventId": 4, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.466Z", + "ParentId": "c4ca4238a0b92382", + "StepStartedDetails": {} + }, + { + "EventType": "StepSucceeded", + "SubType": "Step", + "EventId": 5, + "Id": "98c6f2c2287f4c73", + "EventTimestamp": "2025-12-17T19:41:56.466Z", + "ParentId": "c4ca4238a0b92382", + "StepSucceededDetails": { + "Result": {}, + "RetryDetails": {} + } + }, + { + "EventType": "CallbackSucceeded", + "SubType": "Callback", + "EventId": 6, + "Id": "ea66c06c1e1c05fa", + "EventTimestamp": "2025-12-17T19:41:56.467Z", + "ParentId": "c4ca4238a0b92382", + "CallbackSucceededDetails": { + "Result": { + "Payload": "{\"data\":\"completed\"}" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 7, + "EventTimestamp": "2025-12-17T19:41:56.518Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.457Z", + "EndTimestamp": "2025-12-17T19:41:56.518Z", + "Error": {}, + "RequestId": "651d32b5-1285-4640-a717-4c830e8676f2" + } + }, + { + "EventType": "ContextSucceeded", + "SubType": "WaitForCallback", + "EventId": 8, + "Id": "c4ca4238a0b92382", + "Name": "retry-submitter-callback", + "EventTimestamp": "2025-12-17T19:41:56.522Z", + "ContextSucceededDetails": { + "Result": { + "Payload": "\"{\\\"data\\\":\\\"completed\\\"}\"" + } + } + }, + { + "EventType": "InvocationCompleted", + "EventId": 9, + "EventTimestamp": "2025-12-17T19:41:56.523Z", + "InvocationCompletedDetails": { + "StartTimestamp": "2025-12-17T19:41:56.521Z", + "EndTimestamp": "2025-12-17T19:41:56.523Z", + "Error": {}, + "RequestId": "da3a5e3e-9131-4c18-8061-575ea700dacd" + } + }, + { + "EventType": "ExecutionSucceeded", + "EventId": 10, + "Id": "537ac9c0-a15f-4546-9287-acd7f3cecc26", + "EventTimestamp": "2025-12-17T19:41:56.523Z", + "ExecutionSucceededDetails": { + "Result": { + "Payload": "{\"result\":\"{\\\"data\\\":\\\"completed\\\"}\",\"success\":true}" + } + } + } +] diff --git a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success.test.ts b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success.test.ts index c1592c80..1d1ab4cf 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success.test.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/examples/wait-for-callback/submitter-retry-success/wait-for-callback-submitter-retry-success.test.ts @@ -8,12 +8,12 @@ import { createTests } from "../../../utils/test-helper"; createTests({ handler, invocationType: InvocationType.Event, - tests: (runner) => { + tests: (runner, { assertEventSignatures }) => { it("should complete successfully when submitter succeeds", async () => { const executionPromise = runner.run({ payload: { shouldFail: false } }); const waitForCallbackOp = runner.getOperationByIndex(0); - await waitForCallbackOp.waitForData(WaitingOperationStatus.STARTED); + await waitForCallbackOp.waitForData(WaitingOperationStatus.SUBMITTED); await waitForCallbackOp.sendCallbackSuccess( JSON.stringify({ data: "completed" }), ); @@ -24,6 +24,8 @@ createTests({ result: JSON.stringify({ data: "completed" }), success: true, }); + + assertEventSignatures(execution, "success"); }); it("should fail after exhausting retries when submitter always fails", async () => { @@ -32,6 +34,8 @@ createTests({ const error = execution.getError(); expect(error).toBeDefined(); expect(error?.errorMessage).toContain("Simulated submitter failure"); + + assertEventSignatures(execution, "failure"); }); }, }); diff --git a/packages/aws-durable-execution-sdk-js-examples/src/utils/test-helper.ts b/packages/aws-durable-execution-sdk-js-examples/src/utils/test-helper.ts index 07e608b7..5442d848 100644 --- a/packages/aws-durable-execution-sdk-js-examples/src/utils/test-helper.ts +++ b/packages/aws-durable-execution-sdk-js-examples/src/utils/test-helper.ts @@ -9,7 +9,7 @@ import { LocalDurableTestRunnerSetupParameters, TestResult, } from "@aws/durable-execution-sdk-js-testing"; -import { readFileSync } from "fs"; +import { existsSync, readFileSync, writeFileSync } from "fs"; import path from "path"; export interface FunctionNameMap { @@ -42,10 +42,23 @@ export interface TestDefinition { localRunnerConfig?: LocalDurableTestRunnerSetupParameters; } +export interface EventSignatureConfig { + /** + * Due to API delays or other conditions, the number of invocations can change. + * This property sets a threshold where the number of invocations in the actual history + * must be in a specified range based on the expected history. + */ + invocationCompletedDifference?: number; +} + export interface TestHelper { isTimeSkipping: boolean; isCloud: boolean; - assertEventSignatures(testResult: TestResult, suffix?: string): void; + assertEventSignatures( + testResult: TestResult, + suffix?: string, + eventSignatureConfig?: EventSignatureConfig, + ): void; functionNameMap: FunctionNameMap; } @@ -104,10 +117,34 @@ function assertEventSignatures( actualEvents: Event[], expectedEvents: EventSignature[], isTimeSkipping: boolean = false, + eventSignatureConfig?: EventSignatureConfig, ) { const actualCounts = countEventSignatures(actualEvents, isTimeSkipping); const expectedCounts = countEventSignatures(expectedEvents, isTimeSkipping); + if (eventSignatureConfig?.invocationCompletedDifference) { + const invocationCompletedSignature = JSON.stringify( + createEventSignature({ EventType: EventType.InvocationCompleted }), + ); + + const actualInvocationCompleted = actualCounts.get( + invocationCompletedSignature, + ); + actualCounts.delete(invocationCompletedSignature); + + const expectedInvocationsCompleted = expectedCounts.get( + invocationCompletedSignature, + ); + expectedCounts.delete(invocationCompletedSignature); + + const invocationCompletedDifference = Math.abs( + actualInvocationCompleted - expectedInvocationsCompleted, + ); + expect(invocationCompletedDifference).toBeLessThanOrEqual( + eventSignatureConfig.invocationCompletedDifference, + ); + } + expect(actualCounts).toEqual(expectedCounts); } @@ -139,16 +176,27 @@ function getCallerFile(): string { */ export function createTests(testDef: TestDefinition) { const isIntegrationTest = process.env.NODE_ENV === "integration"; + const generateHistories = process.env.GENERATE_HISTORY === "true"; const isTimeSkipping = (testDef.localRunnerConfig?.skipTime ?? true) && !isIntegrationTest; + if (generateHistories && isTimeSkipping && !isIntegrationTest) { + console.warn("Disabling skipTime since GENERATE_HISTORY is true"); + jest.setTimeout(120000); + } + const testFileName = getCallerFile(); const parsedFunctionName = path.basename(testFileName, ".test.ts"); + let calledAssertEventSignature = false; const testHelper: TestHelper = { - isTimeSkipping, + isTimeSkipping: isTimeSkipping && !generateHistories, isCloud: isIntegrationTest, - assertEventSignatures: (testResult: TestResult, suffix) => { + assertEventSignatures: ( + testResult: TestResult, + suffix, + eventSignatureConfig, + ) => { calledAssertEventSignature = true; const historyFileBasename = suffix @@ -159,10 +207,29 @@ export function createTests(testDef: TestDefinition) { path.dirname(testFileName), `${historyFileBasename}.history.json`, ); + + if (generateHistories) { + if (!existsSync(historyFilePath)) { + console.log(`Generated missing history for ${historyFileBasename}`); + writeFileSync( + historyFilePath, + JSON.stringify(testResult.getHistoryEvents(), null, 2), + ); + return; + } + } + + if (!existsSync(historyFilePath)) { + throw new Error( + `History file ${historyFilePath} does not exist. Please run the test with GENERATE_HISTORY=true to generate it.`, + ); + } + return assertEventSignatures( testResult.getHistoryEvents(), JSON.parse(readFileSync(historyFilePath).toString("utf-8")), testHelper.isTimeSkipping, + eventSignatureConfig, ); }, functionNameMap: isIntegrationTest @@ -220,7 +287,7 @@ export function createTests(testDef: TestDefinition) { beforeAll(() => LocalDurableTestRunner.setupTestEnvironment({ ...testDef.localRunnerConfig, - skipTime: isTimeSkipping, + skipTime: testHelper.isTimeSkipping, }), ); afterAll(() => LocalDurableTestRunner.teardownTestEnvironment());