Skip to content

Commit 42e2e34

Browse files
committed
feat(telemetry): add Durable Execution Telemetry conformance test handlers
1 parent 05cbb20 commit 42e2e34

9 files changed

Lines changed: 442 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
build/
2+
dist/
3+
.aws-sam/
4+
history-*/
5+
report-*.xml
6+
report-*.json
7+
__pycache__/
8+
*.pyc
9+
output/
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Durable Execution Python SDK: Durable Execution Telemetry Conformance Tests
2+
3+
This package answers one question.
4+
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?
5+
6+
Unit tests can assert that the plugin builds a record.
7+
They cannot assert that the record reaches the configured log group on a real invocation.
8+
They cannot assert that it carries the right identity fields for the deployed function.
9+
Those are properties of a deployed function.
10+
So the scenario here is a Lambda function.
11+
The runner deploys it with the plugin configured and invokes it once.
12+
It then fetches the record from CloudWatch Logs and checks it against the requirement.
13+
14+
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`.
15+
This package holds the SDK-specific part: the handler and the SAM template that maps it to the requirement ID.
16+
17+
## Coverage
18+
19+
| Suite | Requirements | What it pins down |
20+
| ----------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
21+
| `telemetry` | `telemetry-1` | One successful single-step execution emits one `SUCCEEDED` record with `input`, `output`, ARN-derived identity fields, and `operationsByName`. |
22+
23+
## Layout
24+
25+
```
26+
src/
27+
telemetry_1_success.py # single step "increment"; plugin + CloudWatchLogsExporter
28+
Makefile # build-Telemetry1Success target used by `sam build`
29+
requirements.txt # core SDK + telemetry exporter, pinned to ${PYTHON_SDK_REF}
30+
template.yaml # declares TelemetryLogGroupName and creates the group
31+
tests/
32+
test_telemetry_examples.py # guards template -> handler wiring and the parameter contract
33+
```
34+
35+
The handler uses the real SDK API only.
36+
It constructs no record and calls no exporter method.
37+
A missing or wrong record is the plugin's defect and is the signal the suite measures.
38+
39+
## Template contract
40+
41+
The runner passes `TelemetryLogGroupName` from the extension.
42+
Extensions have no pre-deploy hook.
43+
So the template creates the group with an `AWS::Logs::LogGroup` resource, and the function depends on it.
44+
The group name reaches the handler through `TELEMETRY_LOG_GROUP_NAME`.
45+
The handler raises at import if that variable is unset.
46+
47+
The `LambdaExecutionRoleArn` role must allow `logs:CreateLogStream` and `logs:PutLogEvents` on the group.
48+
`AWSLambdaBasicDurableExecutionRolePolicy` grants both on `*`.
49+
50+
## Building locally
51+
52+
Prerequisites: Python 3.13 and the AWS SAM CLI.
53+
54+
`src/requirements.txt` installs both SDK packages from git at `${PYTHON_SDK_REF}`.
55+
The ref must be a pushed commit that contains the packages.
56+
57+
```bash
58+
export PYTHON_SDK_REF=$(git rev-parse HEAD) # must already be pushed
59+
sam build --template packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/template.yaml
60+
```
61+
62+
Run the wiring tests from the repository root:
63+
64+
```bash
65+
hatch run test:all packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/tests
66+
```
67+
68+
## Running the suite
69+
70+
Run from a checkout of the conformance repository with the telemetry package installed:
71+
72+
```bash
73+
durable-execution-conformance \
74+
--template <this-repo>/packages/aws-durable-execution-sdk-python-conformance-tests-telemetry/template.yaml \
75+
--language python --region us-west-2 --suite telemetry \
76+
--report console json \
77+
--parameter-overrides LambdaExecutionRoleArn=<role-arn>
78+
```
79+
80+
A caller GitHub workflow is a follow-on.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[build-system]
2+
requires = ["hatchling!=1.32.1,<1.33"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "aws-durable-execution-sdk-python-conformance-tests-telemetry"
7+
version = "0.0.0"
8+
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."
9+
requires-python = ">=3.11"
10+
dependencies = [
11+
"aws-durable-execution-sdk-python==3.0.0",
12+
"aws-durable-execution-sdk-python-telemetry-exporter==1.0.0",
13+
]
14+
15+
[tool.hatch.build.targets.wheel]
16+
# The handlers are flat Lambda modules deployed by SAM from src/, not an
17+
# importable package, so there is nothing to ship in a wheel.
18+
bypass-selection = true
19+
20+
[tool.ruff]
21+
line-length = 88
22+
target-version = "py311"
23+
24+
[tool.ruff.lint]
25+
preview = true
26+
select = ["E4", "E7", "E9", "F", "TID252"] # pycodestyle (E4/E7/E9) + Pyflakes + absolute imports
27+
28+
[tool.ruff.lint.isort]
29+
known-first-party = [
30+
"aws_durable_execution_sdk_python",
31+
"aws_durable_execution_sdk_python_telemetry_exporter",
32+
]
33+
force-single-line = false
34+
lines-after-imports = 2
35+
36+
[tool.ruff.lint.per-file-ignores]
37+
"tests/**" = [
38+
"ARG001",
39+
"ARG002",
40+
"ARG005",
41+
"E402",
42+
"S101",
43+
"PLR2004",
44+
"SIM117",
45+
"TRY301",
46+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: build-Telemetry1Success
2+
3+
build-Telemetry1Success:
4+
python3 -m pip install --upgrade \
5+
--target "$(ARTIFACTS_DIR)" \
6+
--platform manylinux2014_x86_64 \
7+
--implementation cp \
8+
--python-version 3.13 \
9+
--only-binary=:all: \
10+
-r requirements.txt
11+
cp ./*.py "$(ARTIFACTS_DIR)/"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
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
2+
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
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# SPDX-FileCopyrightText: 2026-present Amazon.com, Inc. or its affiliates.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
"""Successful single-step execution for requirement telemetry-1.
5+
6+
The handler uses the real SDK API only. It builds no record and calls no
7+
exporter method. A missing or wrong record is the plugin's defect, and that
8+
defect is the signal the suite measures.
9+
"""
10+
11+
from __future__ import annotations
12+
13+
import os
14+
from typing import Any
15+
16+
from aws_durable_execution_sdk_python import (
17+
DurableContext,
18+
StepContext,
19+
durable_execution,
20+
durable_step,
21+
)
22+
from aws_durable_execution_sdk_python_telemetry_exporter import (
23+
CloudWatchLogsExporter,
24+
ContentConfig,
25+
DurableExecutionTelemetryConfig,
26+
durable_execution_telemetry,
27+
)
28+
29+
30+
# The template sets this variable. Without it the exporter has no target.
31+
# So the module fails at import instead of dropping records silently.
32+
log_group_name = os.environ.get("TELEMETRY_LOG_GROUP_NAME")
33+
if not log_group_name:
34+
raise RuntimeError("TELEMETRY_LOG_GROUP_NAME must be set")
35+
36+
37+
@durable_step
38+
def increment(_step_context: StepContext, value: int) -> int:
39+
return value + 1
40+
41+
42+
@durable_execution(
43+
plugins=[
44+
durable_execution_telemetry(
45+
DurableExecutionTelemetryConfig(
46+
exporters=[CloudWatchLogsExporter(log_group_name=log_group_name)],
47+
emit_mode="on-complete",
48+
sampling_rate=1,
49+
operation_detail="top-level",
50+
content=ContentConfig(input=True, output=True),
51+
)
52+
)
53+
]
54+
)
55+
def handler(event: dict[str, Any], context: DurableContext) -> dict[str, int]:
56+
result: int = context.step(increment(event["value"]), name="increment")
57+
return {"value": result}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
AWSTemplateFormatVersion: "2010-09-09"
2+
Transform: AWS::Serverless-2016-10-31
3+
Description: Python SDK examples for the Durable Execution Telemetry conformance suite
4+
5+
Parameters:
6+
LambdaExecutionRoleArn:
7+
Type: String
8+
Description: Pre-created execution role for the test functions
9+
TelemetryLogGroupName:
10+
Type: String
11+
Description: CloudWatch Logs group that receives Durable Execution Telemetry records
12+
13+
Globals:
14+
Function:
15+
Runtime: python3.13
16+
Architectures:
17+
- x86_64
18+
Timeout: 60
19+
MemorySize: 256
20+
DurableConfig:
21+
ExecutionTimeout: 300
22+
RetentionPeriodInDays: 1
23+
Environment:
24+
Variables:
25+
TELEMETRY_LOG_GROUP_NAME: !Ref TelemetryLogGroupName
26+
27+
Resources:
28+
# Extensions have no pre-deploy hook, so CloudFormation creates the group
29+
# before the runner invokes any function.
30+
TelemetryLogGroup:
31+
Type: AWS::Logs::LogGroup
32+
Properties:
33+
LogGroupName: !Ref TelemetryLogGroupName
34+
RetentionInDays: 1
35+
36+
Telemetry1Success:
37+
Type: AWS::Serverless::Function
38+
DependsOn: TelemetryLogGroup
39+
Metadata:
40+
BuildMethod: makefile
41+
TestingMetadata:
42+
TestDescription:
43+
- telemetry-1
44+
Properties:
45+
CodeUri: src/
46+
Handler: telemetry_1_success.handler
47+
FunctionName: !Sub "${AWS::StackName}-telemetry-1"
48+
Role: !Ref LambdaExecutionRoleArn

0 commit comments

Comments
 (0)