Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
build/
dist/
.aws-sam/
history-*/
report-*.xml
report-*.json
__pycache__/
*.pyc
output/
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Durable Execution Python SDK: Durable Execution Telemetry Conformance Tests

This package answers one question.
Does [`aws-durable-execution-sdk-python-telemetry-exporter`](../aws-durable-execution-sdk-python-telemetry-exporter), with its `CloudWatchLogsExporter`, deliver a complete `DurableExecutionTelemetry` record to CloudWatch Logs for a real Lambda execution?

Unit tests can assert that the plugin builds a record.
They cannot assert that the record reaches the configured log group on a real invocation.
They cannot assert that it carries the right identity fields for the deployed function.
Those are properties of a deployed function.
So the scenario here is a Lambda function.
The runner deploys it with the plugin configured and invokes it once.
It then fetches the record from CloudWatch Logs and checks it against the requirement.

The requirement and the runner live in [`aws/aws-durable-execution-conformance-tests`](https://github.com/aws/aws-durable-execution-conformance-tests), package `aws-durable-execution-conformance-tests-telemetry`.
This package holds the SDK-specific part: the handler and the SAM template that maps it to the requirement ID.

## Coverage

| Suite | Requirements | What it pins down |
| ----------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `telemetry` | `telemetry-1` | One successful single-step execution emits one `SUCCEEDED` record with `input`, `output`, ARN-derived identity fields, and `operationsByName`. |

## Layout

```
src/
telemetry_1_success.py # single step "increment"; plugin + CloudWatchLogsExporter
Makefile # build-Telemetry1Success target used by `sam build`
requirements.txt # core SDK + telemetry exporter, pinned to ${PYTHON_SDK_REF}
template.yaml # declares TelemetryLogGroupName and creates the group
tests/
test_telemetry_examples.py # guards template -> handler wiring and the parameter contract
```

The handler uses the real SDK API only.
It constructs no record and calls no exporter method.
A missing or wrong record is the plugin's defect and is the signal the suite measures.

## Template contract

The runner passes `TelemetryLogGroupName` from the extension.
Extensions have no pre-deploy hook.
So the template creates the group with an `AWS::Logs::LogGroup` resource, and the function depends on it.
The group name reaches the handler through `TELEMETRY_LOG_GROUP_NAME`.
The handler raises at import if that variable is unset.

The `LambdaExecutionRoleArn` role must allow `logs:CreateLogStream` and `logs:PutLogEvents` on the group.
`AWSLambdaBasicDurableExecutionRolePolicy` grants both on `*`.

## Building locally

Prerequisites: Python 3.13 and the AWS SAM CLI.

`src/requirements.txt` installs both SDK packages from git at `${PYTHON_SDK_REF}`.
The ref must be a pushed commit that contains the packages.

```bash
export PYTHON_SDK_REF=$(git rev-parse HEAD) # must already be pushed
sam build --template packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/template.yaml
```

Run the wiring tests from the repository root:

```bash
hatch run test:all packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/tests
```

## Running the suite

Run from a checkout of the conformance repository with the telemetry package installed:

```bash
durable-execution-conformance \
--template <this-repo>/packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/template.yaml \
--language python --region us-west-2 --suite telemetry \
--report console json \
--parameter-overrides LambdaExecutionRoleArn=<role-arn>
```

A caller GitHub workflow is a follow-on.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[build-system]
requires = ["hatchling!=1.32.1,<1.33"]
build-backend = "hatchling.build"

[project]
name = "aws-durable-execution-sdk-python-conformance-tests-telemetry"
version = "0.0.0"
description = "Durable Execution Telemetry conformance test handlers for the AWS Durable Execution SDK for Python, exercised by the aws-durable-execution-conformance-tests telemetry suite."
requires-python = ">=3.11"
dependencies = [
"aws-durable-execution-sdk-python==3.0.0",
"aws-durable-execution-sdk-python-telemetry-exporter==0.0.1",
]

[tool.hatch.build.targets.wheel]
# The handlers are flat Lambda modules deployed by SAM from src/, not an
# importable package, so there is nothing to ship in a wheel.
bypass-selection = true

[tool.ruff]
line-length = 88
target-version = "py311"

[tool.ruff.lint]
preview = true
select = ["E4", "E7", "E9", "F", "TID252"] # pycodestyle (E4/E7/E9) + Pyflakes + absolute imports

[tool.ruff.lint.isort]
known-first-party = [
"aws_durable_execution_sdk_python",
"aws_durable_execution_sdk_python_telemetry_exporter",
]
force-single-line = false
lines-after-imports = 2

[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"ARG001",
"ARG002",
"ARG005",
"E402",
"S101",
"PLR2004",
"SIM117",
"TRY301",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.PHONY: build-Telemetry1Success

build-Telemetry1Success:
python3 -m pip install --upgrade \
--target "$(ARTIFACTS_DIR)" \
--platform manylinux2014_x86_64 \
--implementation cp \
--python-version 3.13 \
--only-binary=:all: \
-r requirements.txt
cp ./*.py "$(ARTIFACTS_DIR)/"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
aws-durable-execution-sdk-python @ git+https://github.com/aws/aws-durable-execution-sdk-python.git@${PYTHON_SDK_REF}#subdirectory=packages/aws-durable-execution-sdk-python
aws-durable-execution-sdk-python-telemetry-exporter @ git+https://github.com/aws/aws-durable-execution-sdk-python.git@${PYTHON_SDK_REF}#subdirectory=packages/aws-durable-execution-sdk-python-telemetry-exporter
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# SPDX-FileCopyrightText: 2026-present Amazon.com, Inc. or its affiliates.
#
# SPDX-License-Identifier: Apache-2.0
"""Successful single-step execution for requirement telemetry-1.

The handler uses the real SDK API only. It builds no record and calls no
exporter method. A missing or wrong record is the plugin's defect, and that
defect is the signal the suite measures.
"""

from __future__ import annotations

import os
from typing import Any

from aws_durable_execution_sdk_python import (
DurableContext,
StepContext,
durable_execution,
durable_step,
)
from aws_durable_execution_sdk_python_telemetry_exporter import (
CloudWatchLogsExporter,
ContentConfig,
DurableExecutionTelemetryConfig,
durable_execution_telemetry,
)


# The template sets this variable. Without it the exporter has no target.
# So the module fails at import instead of dropping records silently.
log_group_name = os.environ.get("TELEMETRY_LOG_GROUP_NAME")
if not log_group_name:
raise RuntimeError("TELEMETRY_LOG_GROUP_NAME must be set")


@durable_step
def increment(_step_context: StepContext, value: int) -> int:
return value + 1


@durable_execution(
plugins=[
durable_execution_telemetry(
DurableExecutionTelemetryConfig(
exporters=[CloudWatchLogsExporter(log_group_name=log_group_name)],
emit_mode="on-complete",
sampling_rate=1,
operation_detail="top-level",
content=ContentConfig(input=True, output=True),
)
)
]
)
def handler(event: dict[str, Any], context: DurableContext) -> dict[str, int]:
result: int = context.step(increment(event["value"]), name="increment")
return {"value": result}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Python SDK examples for the Durable Execution Telemetry conformance suite

Parameters:
LambdaExecutionRoleArn:
Type: String
Description: Pre-created execution role for the test functions
TelemetryLogGroupName:
Type: String
Description: CloudWatch Logs group that receives Durable Execution Telemetry records

Globals:
Function:
Runtime: python3.13
Architectures:
- x86_64
Timeout: 60
MemorySize: 256
DurableConfig:
ExecutionTimeout: 300
RetentionPeriodInDays: 1
Environment:
Variables:
TELEMETRY_LOG_GROUP_NAME: !Ref TelemetryLogGroupName

Resources:
# Extensions have no pre-deploy hook, so CloudFormation creates the group
# before the runner invokes any function.
TelemetryLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Ref TelemetryLogGroupName
RetentionInDays: 1

Telemetry1Success:
Type: AWS::Serverless::Function
DependsOn: TelemetryLogGroup
Metadata:
BuildMethod: makefile
TestingMetadata:
TestDescription:
- telemetry-1
Properties:
CodeUri: src/
Handler: telemetry_1_success.handler
FunctionName: !Sub "${AWS::StackName}-telemetry-1"
Role: !Ref LambdaExecutionRoleArn
Loading
Loading