From c09c0e6b9ca35f2a365065ca6de5610ac54f3f07 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Fri, 24 Jul 2026 23:36:05 +0000 Subject: [PATCH 1/3] ci: install conformance runner from git main Installs the conformance runner from the git main branch (subdirectory packages/aws-durable-execution-conformance-tests) instead of the pinned ==0.1.0 PyPI release, so new upstream suites and requirements are exercised automatically. --- .github/workflows/conformance-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/conformance-tests.yml b/.github/workflows/conformance-tests.yml index 4479d64d..3977329c 100644 --- a/.github/workflows/conformance-tests.yml +++ b/.github/workflows/conformance-tests.yml @@ -95,7 +95,7 @@ jobs: run: python3 scripts/build_examples.py - name: Install conformance runner - run: pip install aws-durable-execution-conformance-tests==0.1.0 + run: pip install "git+https://github.com/aws/aws-durable-execution-conformance-tests.git@main#subdirectory=packages/aws-durable-execution-conformance-tests" - name: Inject Lambda execution role into template env: From 2d8f47787d4489c338c694e35f8c5da011e3c354 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Mon, 27 Jul 2026 21:23:21 +0000 Subject: [PATCH 2/3] test: use context logger in conformance handlers Upstream requirements 1-17, 1-18, 3-11 and 3-17 now specify that the input is logged through the step or child context logger rather than printed to raw stdout, and the runner correlates CloudWatch records to an execution with a JSON filter on the executionArn field that the context logger attaches. Replaces print() with the context logger in those four handlers and sets the JSON log format on the step and child templates, since Lambda's default text format drops the extra fields the filter matches on. This also unblocks 1-7, which already used the step context logger but emitted unstructured records. --- .../handlers/child/child_large_payload.py | 4 +++- .../handlers/child/child_print_only.py | 8 +++++--- .../handlers/step/step_at_most_once_no_retry.py | 6 ++++-- .../handlers/step/step_at_most_once_with_retry.py | 5 +++-- .../template_child.yaml | 7 +++++++ .../template_step.yaml | 7 +++++++ 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py index c58ac3f5..ac852630 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py @@ -24,7 +24,9 @@ def generate_data(_step_context: StepContext) -> str: @durable_with_child_context def large_data_processor(ctx: DurableContext, *, input_1: str) -> str: - print(input_1, flush=True) + # Log through the child context logger so the record carries the execution + # ARN; the child body re-executes on replay to rebuild the large result. + ctx.logger.info(input_1) step_result: str = ctx.step(generate_data()) # Build a large result (>256KB) from the small step result large_result = step_result * 6 # ~300KB diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py index b6433e06..e5e4591b 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py @@ -1,4 +1,4 @@ -"""3-17: Child context with print only (verify no re-execution on replay).""" +"""3-17: Child context with durable logger only (verify no re-execution on replay).""" from typing import Any @@ -11,8 +11,10 @@ @durable_with_child_context -def print_child(_ctx: DurableContext, *, input_1: str) -> str: - print(input_1, flush=True) +def print_child(ctx: DurableContext, *, input_1: str) -> str: + # Log through the child context logger so the record carries the execution + # ARN. A second record would mean the child body was wrongly re-executed. + ctx.logger.info(input_1) return input_1 diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_no_retry.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_no_retry.py index fe43ca91..13aec0f8 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_no_retry.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_no_retry.py @@ -15,8 +15,10 @@ @durable_step -def at_most_once_flaky_step(_step_context: StepContext, *, input_1: str) -> str: - print(input_1, flush=True) +def at_most_once_flaky_step(step_context: StepContext, *, input_1: str) -> str: + # Log through the step context logger so the record carries the execution + # ARN and can be correlated to this durable execution in CloudWatch. + step_context.logger.info(input_1) time.sleep(1) # Allow time for logs to flush to CloudWatch os._exit(1) # Simulate Lambda crash return "unreachable" diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_with_retry.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_with_retry.py index f1dad7c2..906ad0d2 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_with_retry.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/step/step_at_most_once_with_retry.py @@ -19,8 +19,9 @@ @durable_step def at_most_once_step(step_context: StepContext, *, input_1: str) -> str: - # Print input to stdout each time step executes - print(input_1, flush=True) + # Log the input through the step context logger each time the step executes + # so each record carries the execution ARN for CloudWatch correlation. + step_context.logger.info(input_1) time.sleep(1) # Allow time for logs to flush to CloudWatch # The attempt number is the SDK's built-in durable counter from the step diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/template_child.yaml b/packages/aws-durable-execution-sdk-python-conformance-tests/template_child.yaml index 5cd41742..f1bb2473 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/template_child.yaml +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/template_child.yaml @@ -5,6 +5,13 @@ Globals: Runtime: python3.13 Timeout: 60 MemorySize: 128 + # The conformance runner correlates CloudWatch records to a durable + # execution with a JSON filter on the executionArn field the SDK context + # logger attaches. That field only survives under the JSON log format. + LoggingConfig: + LogFormat: JSON + ApplicationLogLevel: INFO + SystemLogLevel: INFO Resources: DurableFunctionRole: Type: AWS::IAM::Role diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/template_step.yaml b/packages/aws-durable-execution-sdk-python-conformance-tests/template_step.yaml index 66a34169..e7ecf112 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/template_step.yaml +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/template_step.yaml @@ -5,6 +5,13 @@ Globals: Runtime: python3.13 Timeout: 60 MemorySize: 128 + # The conformance runner correlates CloudWatch records to a durable + # execution with a JSON filter on the executionArn field the SDK context + # logger attaches. That field only survives under the JSON log format. + LoggingConfig: + LogFormat: JSON + ApplicationLogLevel: INFO + SystemLogLevel: INFO Resources: DurableFunctionRole: Type: AWS::IAM::Role From 56fe4bc778845ca3fc6049e9516a5d80d685e0f4 Mon Sep 17 00:00:00 2001 From: Alex Wang Date: Mon, 27 Jul 2026 21:43:00 +0000 Subject: [PATCH 3/3] test: enable replay logging in child handlers Requirements 3-11 and 3-17 specify replay logging so a child body re-execution stays observable, but the context logger suppresses records while the context is replaying. Rebinds the replay source with with_is_replaying so both handlers log unconditionally while keeping the executionArn the runner correlates on. 3-11 asserts two records: the ReplayChildren re-execution emits no history events, so the log is the only evidence it ran. 3-17 asserts one, and needs replay logging for that count to be meaningful -- with de-duplication an incorrect second execution is hidden. Verified locally: the child body runs twice with is_replaying False then True, yielding two records for 3-11 and one for 3-17. --- .../handlers/child/child_large_payload.py | 7 +++++-- .../handlers/child/child_print_only.py | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py index ac852630..5ee759aa 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_large_payload.py @@ -25,8 +25,11 @@ def generate_data(_step_context: StepContext) -> str: @durable_with_child_context def large_data_processor(ctx: DurableContext, *, input_1: str) -> str: # Log through the child context logger so the record carries the execution - # ARN; the child body re-executes on replay to rebuild the large result. - ctx.logger.info(input_1) + # ARN. The context logger de-duplicates while the context is replaying, so + # rebind the replay source to enable replay logging: the child body re-runs + # in ReplayChildren mode to rebuild the large result, and that re-execution + # emits no history events, making the log the only evidence it happened. + ctx.logger.with_is_replaying(lambda: False).info(input_1) step_result: str = ctx.step(generate_data()) # Build a large result (>256KB) from the small step result large_result = step_result * 6 # ~300KB diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py index e5e4591b..a7db06de 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests/handlers/child/child_print_only.py @@ -13,8 +13,10 @@ @durable_with_child_context def print_child(ctx: DurableContext, *, input_1: str) -> str: # Log through the child context logger so the record carries the execution - # ARN. A second record would mean the child body was wrongly re-executed. - ctx.logger.info(input_1) + # ARN. Rebinding the replay source enables replay logging, which is what + # makes this assertion meaningful: under the default de-duplication an + # incorrect second child execution would be suppressed and still count 1. + ctx.logger.with_is_replaying(lambda: False).info(input_1) return input_1