Skip to content
This repository was archived by the owner on Jun 10, 2026. It is now read-only.

Commit 3a9f1f7

Browse files
committed
feat: build emulator image
1 parent 5e184cb commit 3a9f1f7

15 files changed

Lines changed: 957 additions & 0 deletions

File tree

.github/workflows/ecr-release.yml

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
name: ecr-release.yml
2+
on:
3+
on:
4+
push:
5+
branches: [ "feat/publish-emulator-image" ]
6+
release:
7+
types: [published]
8+
9+
permissions:
10+
contents: read
11+
id-token: write # This is required for requesting the JWT
12+
13+
env:
14+
path_to_dockerfile: "bin/DockerFile"
15+
docker_build_dir: "bin"
16+
aws_region: "us-east-1"
17+
ecr_repository_name: "o4w4w0v6/aws-durable-execution-emulator"
18+
19+
jobs:
20+
build-and-upload-image-to-ecr:
21+
runs-on: ubuntu-latest
22+
outputs:
23+
full_image_arm64: ${{ steps.build-publish.outputs.full_image_arm64 }}
24+
full_image_x86_64: ${{ steps.build-publish.outputs.full_image_x86_64 }}
25+
ecr_registry_repository: ${{ steps.build-publish.outputs.ecr_registry_repository }}
26+
strategy:
27+
matrix:
28+
include:
29+
- arch: x86_64
30+
- arch: arm64
31+
steps:
32+
- name: Grab version from generate-version job
33+
id: version
34+
env:
35+
VERSION: $${{ github.event.release.name }}
36+
run: |
37+
echo "$VERSION"
38+
- uses: actions/checkout@v6
39+
- name: Set up Python
40+
uses: actions/setup-python@v6
41+
with:
42+
python-version: "3.13"
43+
44+
- name: Install dependencies
45+
run: |
46+
python -m pip install --upgrade pip
47+
pip install hatch
48+
- name: Set up QEMU for multi-platform builds
49+
if: matrix.arch == 'arm64'
50+
uses: docker/setup-qemu-action@v3
51+
with:
52+
platforms: arm64
53+
- name: Configure AWS Credentials
54+
uses: aws-actions/configure-aws-credentials@v4
55+
with:
56+
role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }}
57+
aws-region: ${{ env.aws_region }}
58+
- name: Login to Amazon ECR
59+
id: login-ecr-public
60+
uses: aws-actions/amazon-ecr-login@v2
61+
with:
62+
registry-type: public
63+
- name: Build, tag, and push image to Amazon ECR
64+
id: build-publish
65+
shell: bash
66+
env:
67+
ECR_REGISTRY: ${{ steps.login-ecr-public.outputs.registry }}
68+
ECR_REPOSITORY: ${{ env.ecr_repository_name }}
69+
IMAGE_TAG: "${{ env.image_tag }}${{ needs.generate-version.outputs.version }}"
70+
PER_ARCH_IMAGE_TAG: "${{ matrix.arch }}${{ needs.generate-version.outputs.version }}"
71+
run: |
72+
if [ "${{ matrix.arch }}" = "x86_64" ]; then
73+
docker build --platform linux/amd64 --provenance false "${{ env.docker_build_dir }}" -f "${{ env.path_to_dockerfile }}" -t "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
74+
else
75+
docker build --platform linux/arm64 --provenance false "${{ env.docker_build_dir }}" -f "${{ env.path_to_dockerfile }}" -t "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
76+
fi
77+
docker push "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
78+
echo "IMAGE $PER_ARCH_IMAGE_TAG is pushed to $ECR_REGISTRY/$ECR_REPOSITORY"
79+
echo "image_tag=$PER_ARCH_IMAGE_TAG"
80+
echo "full_image=$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
81+
echo "ecr_registry_repository=$ECR_REGISTRY/$ECR_REPOSITORY" >> $GITHUB_OUTPUT
82+
echo "full_image_${{ matrix.arch }}=$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG" >> $GITHUB_OUTPUT
83+
create-ecr-manifest-per-arch:
84+
runs-on: ubuntu-latest
85+
needs: [build-and-upload-image-to-ecr]
86+
steps:
87+
- name: Grab image and registry/repository name from previous steps
88+
id: ecr_names
89+
env:
90+
ECR_REGISTRY_REPOSITORY: ${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}
91+
FULL_IMAGE_ARM64: ${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}
92+
FULL_IMAGE_X86_64: ${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}
93+
run: |
94+
echo "full_image_arm64=$FULL_IMAGE_ARM64"
95+
echo "ecr_registry_repository=$ECR_REGISTRY_REPOSITORY"
96+
echo "full_image_x86_64=$FULL_IMAGE_X86_64"
97+
- name: Configure AWS Credentials
98+
uses: aws-actions/configure-aws-credentials@v4
99+
with:
100+
role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }}
101+
aws-region: ${{ env.aws_region }}
102+
- name: Login to Amazon ECR
103+
id: login-ecr-public
104+
uses: aws-actions/amazon-ecr-login@v2
105+
with:
106+
registry-type: public
107+
- name: Create ECR manifest with explicit tag
108+
id: create-ecr-manifest-explicit
109+
run: |
110+
docker manifest create "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:$${{ github.event.release.name }}" \
111+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \
112+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}"
113+
- name: Annotate ECR manifest with explicit arm64 tag
114+
id: annotate-ecr-manifest-explicit-arm64
115+
run: |
116+
docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:$${{ github.event.release.name }}" \
117+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \
118+
--arch arm64 \
119+
--os linux
120+
- name: Annotate ECR manifest with explicit amd64 tag
121+
id: annotate-ecr-manifest-explicit-amd64
122+
run: |
123+
docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:$${{ github.event.release.name }}" \
124+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \
125+
--arch amd64 \
126+
--os linux
127+
- name: Push ECR manifest with explicit version
128+
id: push-ecr-manifest-explicit
129+
run: |
130+
docker manifest push "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}:$${{ github.event.release.name }}"
131+
- name: Create ECR manifest with latest tag
132+
id: create-ecr-manifest-latest
133+
run: |
134+
docker manifest create "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \
135+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \
136+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}"
137+
- name: Annotate ECR manifest with latest tag arm64
138+
id: annotate-ecr-manifest-latest-arm64
139+
run: |
140+
docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \
141+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_arm64 }}" \
142+
--arch arm64 \
143+
--os linux
144+
- name: Annotate ECR manifest with latest tag amd64
145+
id: annotate-ecr-manifest-latest-amd64
146+
run: |
147+
docker manifest annotate "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}" \
148+
"${{ needs.build-and-upload-image-to-ecr.outputs.full_image_x86_64 }}" \
149+
--arch amd64 \
150+
--os linux
151+
- name: Push ECR manifest with latest
152+
id: push-ecr-manifest-latest
153+
run: |
154+
docker manifest push "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ dist/
3535

3636
examples/build/*
3737
examples/*.zip
38+
39+
durable-executions.db*

emulator/DockerFile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM public.ecr.aws/ubuntu/python:3.13-25.10_stable
2+
3+
COPY emulator /emulator
4+
5+
RUN hatch run pip install -e .

emulator/README.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# AWS Durable Execution Emulator
2+
3+
A local emulator for AWS Lambda durable functions that enables local development and testing of durable function applications. Powered by the AWS Durable Execution Testing SDK for Python.
4+
5+
## Overview
6+
7+
The AWS Lambda Durable Execution Emulator provides a local development environment for building and testing durable function applications before deploying to AWS Lambda. It uses the AWS Durable Execution Testing SDK for Python as its execution engine, providing robust durable execution capabilities with full AWS API compatibility.
8+
9+
## Features
10+
11+
- **Local Development**: Run durable functions locally without AWS infrastructure
12+
- **API Compatibility**: Compatible with AWS Lambda Durable Functions APIs
13+
- **Health Check Endpoint**: Built-in health monitoring
14+
- **Logging**: Configurable logging levels for debugging
15+
- **Testing Support**: Built-in test framework support
16+
17+
## Installation
18+
19+
### From source
20+
21+
```bash
22+
git clone https://github.com/aws/aws-lambda-durable-functions-emulator.git
23+
cd aws-lambda-durable-functions-emulator
24+
hatch run pip install -e .
25+
```
26+
27+
## Usage
28+
29+
### Starting the Emulator
30+
31+
```bash
32+
# Using the installed command
33+
durable-functions-emulator
34+
35+
# Or using hatch for development
36+
hatch run dev
37+
38+
# With custom host and port
39+
durable-functions-emulator --host 0.0.0.0 --port 8080
40+
```
41+
42+
### Environment Variables
43+
44+
- `HOST`: Server host (default: 0.0.0.0)
45+
- `PORT`: Server port (default: 5000)
46+
- `LOG`: Logging level (default: INFO)
47+
- `STORAGE_DIR`: Directory for persistent storage
48+
- `EXECUTION_STORE_TYPE`: Type of execution store (default: sqlite)
49+
- `filesystem`: File-based storage
50+
- `sqlite`: SQLite database storage (default)
51+
- `LAMBDA_ENDPOINT`: Lambda endpoint URL for testing
52+
- `LOCAL_RUNNER_ENDPOINT`: Local runner endpoint URL
53+
- `LOCAL_RUNNER_REGION`: AWS region for local runner
54+
- `LOCAL_RUNNER_MODE`: Runner mode (default: local)
55+
56+
### Health Check
57+
58+
The emulator provides a health check endpoint:
59+
60+
```bash
61+
curl http://localhost:5000/ping
62+
```
63+
64+
## Development
65+
66+
### Prerequisites
67+
68+
- Python 3.13+
69+
- [Hatch](https://hatch.pypa.io/) for project management
70+
71+
### Setup
72+
73+
```bash
74+
git clone https://github.com/aws/aws-lambda-durable-functions-emulator.git
75+
cd aws-lambda-durable-functions-emulator
76+
hatch run pip install -e .
77+
```
78+
79+
### Running Tests
80+
81+
```bash
82+
# Run all tests
83+
hatch run test
84+
85+
# Run with coverage
86+
hatch run test:cov
87+
88+
# Type checking
89+
hatch run types:check
90+
```
91+
92+
### Building
93+
94+
```bash
95+
hatch build
96+
```
97+
98+
## API Reference
99+
100+
### Health Check
101+
102+
- **GET** `/ping` - Returns emulator status
103+
104+
### Durable Execution APIs
105+
106+
- **POST** `/2025-12-01/durable-execution-state/<token>/checkpoint` - Checkpoint execution state
107+
- **GET** `/2025-12-01/durable-execution-state/<token>/getState` - Get execution state
108+
- **GET** `/2025-12-01/durable-executions/<arn>` - Get execution details
109+
- **GET** `/2025-12-01/durable-executions/<arn>/history` - Get execution history
110+
111+
### Callback APIs
112+
113+
- **POST** `/2025-12-01/durable-execution-callbacks/<id>/succeed` - Send success callback
114+
- **POST** `/2025-12-01/durable-execution-callbacks/<id>/fail` - Send failure callback
115+
- **POST** `/2025-12-01/durable-execution-callbacks/<id>/heartbeat` - Send heartbeat callback
116+
117+
## Contributing
118+
119+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
120+
121+
## License
122+
123+
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
124+
125+
## Security
126+
127+
See [CONTRIBUTING.md](CONTRIBUTING.md#security-issue-notifications) for more information.

0 commit comments

Comments
 (0)