aws-durable-execution-sdk-python 1.4.0__tar.gz → 1.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/.gitignore +7 -1
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/PKG-INFO +7 -32
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/README.md +5 -28
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/pyproject.toml +9 -12
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/__about__.py +1 -1
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/__init__.py +8 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/concurrency/executor.py +91 -28
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/config.py +120 -14
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/context.py +141 -15
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/exceptions.py +100 -42
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/execution.py +102 -109
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/identifier.py +10 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/lambda_service.py +107 -1
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/child.py +51 -31
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/map.py +15 -2
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/parallel.py +25 -4
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/step.py +13 -3
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py +9 -1
- aws_durable_execution_sdk_python-1.6.0/src/aws_durable_execution_sdk_python/plugin.py +407 -0
- aws_durable_execution_sdk_python-1.6.0/src/aws_durable_execution_sdk_python/retries.py +377 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/state.py +154 -25
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/types.py +3 -1
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/concurrency_test.py +389 -36
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/config_test.py +0 -11
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/context_test.py +389 -28
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/e2e/checkpoint_response_int_test.py +11 -11
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/e2e/execution_int_test.py +7 -7
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/e2e/map_with_concurrent_waits_int_test.py +2 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/exceptions_test.py +145 -34
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/execution_test.py +577 -150
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/lambda_service_test.py +163 -14
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/logger_test.py +8 -2
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/callback_test.py +92 -34
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/child_test.py +349 -27
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/invoke_test.py +101 -35
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/map_test.py +380 -172
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/parallel_test.py +365 -174
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/step_test.py +112 -24
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/wait_for_condition_test.py +140 -31
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/wait_test.py +29 -11
- aws_durable_execution_sdk_python-1.6.0/tests/plugin_test.py +787 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/retries_test.py +147 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/state_test.py +788 -6
- aws_durable_execution_sdk_python-1.6.0/tests/with_retry_test.py +372 -0
- aws_durable_execution_sdk_python-1.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +0 -91
- aws_durable_execution_sdk_python-1.4.0/.github/ISSUE_TEMPLATE/config.yml +0 -5
- aws_durable_execution_sdk_python-1.4.0/.github/ISSUE_TEMPLATE/documentation.yml +0 -36
- aws_durable_execution_sdk_python-1.4.0/.github/ISSUE_TEMPLATE/feature_request.yml +0 -57
- aws_durable_execution_sdk_python-1.4.0/.github/dependabot.yml +0 -14
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/ci.yml +0 -53
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/integration-tests.yml +0 -182
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/lintcommit.js +0 -178
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/notify_slack.yml +0 -39
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/pypi-publish.yml +0 -71
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/scorecard.yml +0 -80
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/sync-package.yml +0 -72
- aws_durable_execution_sdk_python-1.4.0/.github/workflows/test-parser.yml +0 -24
- aws_durable_execution_sdk_python-1.4.0/AGENTS.md +0 -934
- aws_durable_execution_sdk_python-1.4.0/CODE_OF_CONDUCT.md +0 -4
- aws_durable_execution_sdk_python-1.4.0/CONTRIBUTING.md +0 -324
- aws_durable_execution_sdk_python-1.4.0/docs/advanced/error-handling.md +0 -955
- aws_durable_execution_sdk_python-1.4.0/docs/advanced/serialization.md +0 -771
- aws_durable_execution_sdk_python-1.4.0/docs/advanced/testing-modes.md +0 -495
- aws_durable_execution_sdk_python-1.4.0/docs/api-reference/.gitkeep +0 -1
- aws_durable_execution_sdk_python-1.4.0/docs/architecture.md +0 -505
- aws_durable_execution_sdk_python-1.4.0/docs/best-practices.md +0 -850
- aws_durable_execution_sdk_python-1.4.0/docs/core/callbacks.md +0 -877
- aws_durable_execution_sdk_python-1.4.0/docs/core/child-contexts.md +0 -703
- aws_durable_execution_sdk_python-1.4.0/docs/core/invoke.md +0 -774
- aws_durable_execution_sdk_python-1.4.0/docs/core/logger.md +0 -737
- aws_durable_execution_sdk_python-1.4.0/docs/core/map.md +0 -589
- aws_durable_execution_sdk_python-1.4.0/docs/core/parallel.md +0 -911
- aws_durable_execution_sdk_python-1.4.0/docs/core/steps.md +0 -597
- aws_durable_execution_sdk_python-1.4.0/docs/core/wait.md +0 -445
- aws_durable_execution_sdk_python-1.4.0/docs/getting-started.md +0 -293
- aws_durable_execution_sdk_python-1.4.0/docs/index.md +0 -205
- aws_durable_execution_sdk_python-1.4.0/docs/testing-patterns/.gitkeep +0 -1
- aws_durable_execution_sdk_python-1.4.0/docs/testing-patterns/basic-tests.md +0 -701
- aws_durable_execution_sdk_python-1.4.0/docs/testing-patterns/complex-workflows.md +0 -675
- aws_durable_execution_sdk_python-1.4.0/docs/testing-patterns/stores.md +0 -262
- aws_durable_execution_sdk_python-1.4.0/ops/__tests__/test_parse_sdk_branch.py +0 -84
- aws_durable_execution_sdk_python-1.4.0/ops/ci-checks.sh +0 -15
- aws_durable_execution_sdk_python-1.4.0/ops/parse_sdk_branch.py +0 -31
- aws_durable_execution_sdk_python-1.4.0/src/aws_durable_execution_sdk_python/retries.py +0 -174
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/LICENSE +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/NOTICE +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/.gitignore +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/concurrency/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/concurrency/models.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/logger.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/base.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/callback.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/invoke.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/operation/wait.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/py.typed +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/serdes.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/suspend.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/threading.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/src/aws_durable_execution_sdk_python/waits.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/durable_executions_python_language_sdk_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/e2e/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/operation/base_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/serdes_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/suspend_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/test_helpers.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/threading_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/types_test.py +0 -0
- {aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/tests/waits_test.py +0 -0
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aws-durable-execution-sdk-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: AWS Durable Execution SDK for Python
|
|
5
5
|
Project-URL: Documentation, https://github.com/aws/aws-durable-execution-sdk-python#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/aws/aws-durable-execution-sdk-python/issues
|
|
7
7
|
Project-URL: Source, https://github.com/aws/aws-durable-execution-sdk-python
|
|
8
|
-
Author-email:
|
|
8
|
+
Author-email: AWS durable-execution-dev <durable-execution-dev@amazon.com>
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
License-File: NOTICE
|
|
12
10
|
Classifier: Development Status :: 4 - Beta
|
|
13
11
|
Classifier: Programming Language :: Python
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -27,7 +25,7 @@ Description-Content-Type: text/markdown
|
|
|
27
25
|
[](https://pypi.org/project/aws-durable-execution-sdk-python)
|
|
28
26
|
[](https://pypi.org/project/aws-durable-execution-sdk-python)
|
|
29
27
|
[](https://scorecard.dev/viewer/?uri=github.com/aws/aws-durable-execution-sdk-python)
|
|
30
|
-
[](LICENSE)
|
|
28
|
+
[](https://github.com/aws/aws-durable-execution-sdk-python/blob/main/LICENSE)
|
|
31
29
|
|
|
32
30
|
-----
|
|
33
31
|
|
|
@@ -91,33 +89,10 @@ def handler(event: dict, context: DurableContext) -> dict:
|
|
|
91
89
|
|
|
92
90
|
## 📚 Documentation
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
- **[Documentation index](docs/index.md)** - SDK Overview and navigation
|
|
92
|
+
The complete documentation for the AWS Durable Execution SDK for Python lives on the AWS Documentation site:
|
|
96
93
|
|
|
97
|
-
**
|
|
98
|
-
- [
|
|
99
|
-
|
|
100
|
-
**Core operations:**
|
|
101
|
-
- [Steps](docs/core/steps.md) - Execute code with automatic checkpointing and retry support
|
|
102
|
-
- [Wait operations](docs/core/wait.md) - Pause execution without blocking Lambda resources
|
|
103
|
-
- [Callbacks](docs/core/callbacks.md) - Wait for external systems to respond
|
|
104
|
-
- [Invoke operations](docs/core/invoke.md) - Call other durable functions and compose workflows
|
|
105
|
-
- [Child contexts](docs/core/child-contexts.md) - Organize complex workflows into isolated units
|
|
106
|
-
- [Parallel operations](docs/core/parallel.md) - Run multiple operations concurrently
|
|
107
|
-
- [Map operations](docs/core/map.md) - Process collections in parallel with batching
|
|
108
|
-
- [Logger integration](docs/core/logger.md) - Add structured logging to track execution
|
|
109
|
-
|
|
110
|
-
**Advanced topics:**
|
|
111
|
-
- [Error handling](docs/advanced/error-handling.md) - Handle failures and implement retry strategies
|
|
112
|
-
- [Testing modes](docs/advanced/testing-modes.md) - Run tests locally or against deployed Lambda functions
|
|
113
|
-
- [Testing patterns](docs/testing-patterns/basic-tests.md) - Practical testing examples
|
|
114
|
-
- [Serialization](docs/advanced/serialization.md) - Customize how data is serialized in checkpoints
|
|
115
|
-
|
|
116
|
-
**Architecture:**
|
|
117
|
-
- [Architecture diagrams](docs/architecture.md) - Class diagrams and concurrency flows
|
|
118
|
-
|
|
119
|
-
**API reference:**
|
|
120
|
-
- API reference docs are in progress. Use the core operation docs above for now.
|
|
94
|
+
- **[AWS Durable Execution Documentation](https://docs.aws.amazon.com/durable-execution/)** - Concepts, getting started, core operations, advanced topics, and API reference
|
|
95
|
+
- **[AWS Lambda Durable Functions Guide](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)** - How durable functions work on Lambda
|
|
121
96
|
|
|
122
97
|
## 💬 Feedback & Support
|
|
123
98
|
|
|
@@ -128,4 +103,4 @@ def handler(event: dict, context: DurableContext) -> dict:
|
|
|
128
103
|
|
|
129
104
|
## 📄 License
|
|
130
105
|
|
|
131
|
-
See the [LICENSE](LICENSE) file for our project's licensing.
|
|
106
|
+
See the [LICENSE](https://github.com/aws/aws-durable-execution-sdk-python/blob/main/LICENSE) file for our project's licensing.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://pypi.org/project/aws-durable-execution-sdk-python)
|
|
5
5
|
[](https://pypi.org/project/aws-durable-execution-sdk-python)
|
|
6
6
|
[](https://scorecard.dev/viewer/?uri=github.com/aws/aws-durable-execution-sdk-python)
|
|
7
|
-
[](LICENSE)
|
|
7
|
+
[](https://github.com/aws/aws-durable-execution-sdk-python/blob/main/LICENSE)
|
|
8
8
|
|
|
9
9
|
-----
|
|
10
10
|
|
|
@@ -68,33 +68,10 @@ def handler(event: dict, context: DurableContext) -> dict:
|
|
|
68
68
|
|
|
69
69
|
## 📚 Documentation
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
- **[Documentation index](docs/index.md)** - SDK Overview and navigation
|
|
71
|
+
The complete documentation for the AWS Durable Execution SDK for Python lives on the AWS Documentation site:
|
|
73
72
|
|
|
74
|
-
**
|
|
75
|
-
- [
|
|
76
|
-
|
|
77
|
-
**Core operations:**
|
|
78
|
-
- [Steps](docs/core/steps.md) - Execute code with automatic checkpointing and retry support
|
|
79
|
-
- [Wait operations](docs/core/wait.md) - Pause execution without blocking Lambda resources
|
|
80
|
-
- [Callbacks](docs/core/callbacks.md) - Wait for external systems to respond
|
|
81
|
-
- [Invoke operations](docs/core/invoke.md) - Call other durable functions and compose workflows
|
|
82
|
-
- [Child contexts](docs/core/child-contexts.md) - Organize complex workflows into isolated units
|
|
83
|
-
- [Parallel operations](docs/core/parallel.md) - Run multiple operations concurrently
|
|
84
|
-
- [Map operations](docs/core/map.md) - Process collections in parallel with batching
|
|
85
|
-
- [Logger integration](docs/core/logger.md) - Add structured logging to track execution
|
|
86
|
-
|
|
87
|
-
**Advanced topics:**
|
|
88
|
-
- [Error handling](docs/advanced/error-handling.md) - Handle failures and implement retry strategies
|
|
89
|
-
- [Testing modes](docs/advanced/testing-modes.md) - Run tests locally or against deployed Lambda functions
|
|
90
|
-
- [Testing patterns](docs/testing-patterns/basic-tests.md) - Practical testing examples
|
|
91
|
-
- [Serialization](docs/advanced/serialization.md) - Customize how data is serialized in checkpoints
|
|
92
|
-
|
|
93
|
-
**Architecture:**
|
|
94
|
-
- [Architecture diagrams](docs/architecture.md) - Class diagrams and concurrency flows
|
|
95
|
-
|
|
96
|
-
**API reference:**
|
|
97
|
-
- API reference docs are in progress. Use the core operation docs above for now.
|
|
73
|
+
- **[AWS Durable Execution Documentation](https://docs.aws.amazon.com/durable-execution/)** - Concepts, getting started, core operations, advanced topics, and API reference
|
|
74
|
+
- **[AWS Lambda Durable Functions Guide](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)** - How durable functions work on Lambda
|
|
98
75
|
|
|
99
76
|
## 💬 Feedback & Support
|
|
100
77
|
|
|
@@ -105,4 +82,4 @@ def handler(event: dict, context: DurableContext) -> dict:
|
|
|
105
82
|
|
|
106
83
|
## 📄 License
|
|
107
84
|
|
|
108
|
-
See the [LICENSE](LICENSE) file for our project's licensing.
|
|
85
|
+
See the [LICENSE](https://github.com/aws/aws-durable-execution-sdk-python/blob/main/LICENSE) file for our project's licensing.
|
{aws_durable_execution_sdk_python-1.4.0 → aws_durable_execution_sdk_python-1.6.0}/pyproject.toml
RENAMED
|
@@ -10,7 +10,7 @@ readme = "README.md"
|
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = []
|
|
13
|
-
authors = [{ name = "
|
|
13
|
+
authors = [{ name = "AWS durable-execution-dev", email = "durable-execution-dev@amazon.com" }]
|
|
14
14
|
classifiers = [
|
|
15
15
|
"Development Status :: 4 - Beta",
|
|
16
16
|
"Programming Language :: Python",
|
|
@@ -28,23 +28,20 @@ Documentation = "https://github.com/aws/aws-durable-execution-sdk-python#readme"
|
|
|
28
28
|
Issues = "https://github.com/aws/aws-durable-execution-sdk-python/issues"
|
|
29
29
|
Source = "https://github.com/aws/aws-durable-execution-sdk-python"
|
|
30
30
|
|
|
31
|
+
[tool.hatch.build.targets.sdist.force-include]
|
|
32
|
+
"../../LICENSE" = "LICENSE"
|
|
33
|
+
"../../NOTICE" = "NOTICE"
|
|
34
|
+
|
|
31
35
|
[tool.hatch.build.targets.wheel]
|
|
32
36
|
packages = ["src/aws_durable_execution_sdk_python"]
|
|
33
37
|
|
|
38
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
39
|
+
"../../LICENSE" = "aws_durable_execution_sdk_python/LICENSE"
|
|
40
|
+
"../../NOTICE" = "aws_durable_execution_sdk_python/NOTICE"
|
|
41
|
+
|
|
34
42
|
[tool.hatch.version]
|
|
35
43
|
path = "src/aws_durable_execution_sdk_python/__about__.py"
|
|
36
44
|
|
|
37
|
-
[tool.hatch.envs.test]
|
|
38
|
-
dependencies = ["coverage[toml]", "pytest", "pytest-cov"]
|
|
39
|
-
|
|
40
|
-
[tool.hatch.envs.test.scripts]
|
|
41
|
-
cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src/aws_durable_execution_sdk_python --cov-fail-under=98"
|
|
42
|
-
|
|
43
|
-
[tool.hatch.envs.types]
|
|
44
|
-
extra-dependencies = ["mypy>=1.0.0", "pytest", "boto3-stubs[lambda]"]
|
|
45
|
-
[tool.hatch.envs.types.scripts]
|
|
46
|
-
check = "mypy --install-types --non-interactive {args:src/aws_durable_execution_sdk_python tests}"
|
|
47
|
-
|
|
48
45
|
[tool.coverage.run]
|
|
49
46
|
source_pkgs = ["aws_durable_execution_sdk_python"]
|
|
50
47
|
branch = true
|
|
@@ -7,8 +7,10 @@ from aws_durable_execution_sdk_python.__about__ import __version__
|
|
|
7
7
|
# Helper decorators - commonly used for step functions
|
|
8
8
|
# Concurrency
|
|
9
9
|
from aws_durable_execution_sdk_python.concurrency.models import BatchResult
|
|
10
|
+
from aws_durable_execution_sdk_python.config import ParallelBranch
|
|
10
11
|
from aws_durable_execution_sdk_python.context import (
|
|
11
12
|
DurableContext,
|
|
13
|
+
durable_parallel_branch,
|
|
12
14
|
durable_step,
|
|
13
15
|
durable_wait_for_callback,
|
|
14
16
|
durable_with_child_context,
|
|
@@ -23,20 +25,26 @@ from aws_durable_execution_sdk_python.exceptions import (
|
|
|
23
25
|
|
|
24
26
|
# Core decorator - used in every durable function
|
|
25
27
|
from aws_durable_execution_sdk_python.execution import durable_execution
|
|
28
|
+
from aws_durable_execution_sdk_python.retries import WithRetryConfig, with_retry
|
|
26
29
|
|
|
27
30
|
# Essential context types - passed to user functions
|
|
28
31
|
from aws_durable_execution_sdk_python.types import StepContext
|
|
29
32
|
|
|
33
|
+
|
|
30
34
|
__all__ = [
|
|
31
35
|
"BatchResult",
|
|
32
36
|
"DurableContext",
|
|
33
37
|
"DurableExecutionsError",
|
|
34
38
|
"InvocationError",
|
|
39
|
+
"ParallelBranch",
|
|
35
40
|
"StepContext",
|
|
36
41
|
"ValidationError",
|
|
42
|
+
"WithRetryConfig",
|
|
37
43
|
"__version__",
|
|
38
44
|
"durable_execution",
|
|
45
|
+
"durable_parallel_branch",
|
|
39
46
|
"durable_step",
|
|
40
47
|
"durable_wait_for_callback",
|
|
41
48
|
"durable_with_child_context",
|
|
49
|
+
"with_retry",
|
|
42
50
|
]
|
|
@@ -20,14 +20,17 @@ from aws_durable_execution_sdk_python.concurrency.models import (
|
|
|
20
20
|
ExecutionCounters,
|
|
21
21
|
SuspendResult,
|
|
22
22
|
)
|
|
23
|
-
from aws_durable_execution_sdk_python.config import
|
|
23
|
+
from aws_durable_execution_sdk_python.config import (
|
|
24
|
+
ChildConfig,
|
|
25
|
+
NestingType,
|
|
26
|
+
)
|
|
24
27
|
from aws_durable_execution_sdk_python.exceptions import (
|
|
25
28
|
OrphanedChildException,
|
|
26
29
|
SuspendExecution,
|
|
27
30
|
TimedSuspendExecution,
|
|
28
31
|
)
|
|
29
32
|
from aws_durable_execution_sdk_python.identifier import OperationIdentifier
|
|
30
|
-
from aws_durable_execution_sdk_python.lambda_service import ErrorObject
|
|
33
|
+
from aws_durable_execution_sdk_python.lambda_service import ErrorObject, OperationType
|
|
31
34
|
from aws_durable_execution_sdk_python.operation.child import child_handler
|
|
32
35
|
|
|
33
36
|
|
|
@@ -56,7 +59,7 @@ class TimerScheduler:
|
|
|
56
59
|
"""Manage timed suspend tasks with a background timer thread."""
|
|
57
60
|
|
|
58
61
|
def __init__(
|
|
59
|
-
self, resubmit_callback: Callable[[ExecutableWithState], None]
|
|
62
|
+
self, resubmit_callback: Callable[[list[ExecutableWithState]], None]
|
|
60
63
|
) -> None:
|
|
61
64
|
self.resubmit_callback = resubmit_callback
|
|
62
65
|
self._pending_resumes: list[tuple[float, int, ExecutableWithState]] = []
|
|
@@ -111,18 +114,31 @@ class TimerScheduler:
|
|
|
111
114
|
|
|
112
115
|
current_time = time.time()
|
|
113
116
|
if current_time >= next_resume_time:
|
|
114
|
-
#
|
|
117
|
+
# Drain every due resume under the lock, transitioning each to
|
|
118
|
+
# PENDING atomically with the pop. Keeping pop+reset_to_pending
|
|
119
|
+
# together is required: should_execution_suspend reads branch
|
|
120
|
+
# status without this lock, so an item that is removed from the
|
|
121
|
+
# heap but still SUSPENDED_WITH_TIMEOUT could trigger a spurious
|
|
122
|
+
# parent suspend.
|
|
123
|
+
ready: list[ExecutableWithState] = []
|
|
115
124
|
with self._lock:
|
|
116
|
-
|
|
117
|
-
# since the first peek on next_resume_time further up
|
|
118
|
-
if ( # pragma: no branch
|
|
125
|
+
while (
|
|
119
126
|
self._pending_resumes
|
|
120
127
|
and self._pending_resumes[0][0] <= current_time
|
|
121
128
|
):
|
|
122
129
|
_, _, exe_state = heapq.heappop(self._pending_resumes)
|
|
123
130
|
if exe_state.can_resume:
|
|
124
131
|
exe_state.reset_to_pending()
|
|
125
|
-
|
|
132
|
+
ready.append(exe_state)
|
|
133
|
+
# Resubmit outside the lock. Only the heap pop and the PENDING
|
|
134
|
+
# transition need the lock. The checkpoint refresh is a blocking
|
|
135
|
+
# network call and the submit hands work to the pool, so running
|
|
136
|
+
# them off the lock keeps timed resumes from serializing behind
|
|
137
|
+
# the network round trip and keeps the timer thread from
|
|
138
|
+
# re-entering this non-reentrant lock when a submitted future
|
|
139
|
+
# completes inline and its done-callback calls schedule_resume.
|
|
140
|
+
if ready:
|
|
141
|
+
self.resubmit_callback(ready)
|
|
126
142
|
else:
|
|
127
143
|
# Wait until next resume time
|
|
128
144
|
wait_time = min(next_resume_time - current_time, 0.1)
|
|
@@ -143,6 +159,7 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
143
159
|
serdes: SerDes | None,
|
|
144
160
|
item_serdes: SerDes | None = None,
|
|
145
161
|
summary_generator: SummaryGenerator | None = None,
|
|
162
|
+
nesting_type: NestingType = NestingType.NESTED,
|
|
146
163
|
):
|
|
147
164
|
"""Initialize ConcurrentExecutor.
|
|
148
165
|
|
|
@@ -160,10 +177,12 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
160
177
|
self.sub_type_iteration = sub_type_iteration
|
|
161
178
|
self.name_prefix = name_prefix
|
|
162
179
|
self.summary_generator = summary_generator
|
|
180
|
+
self.nesting_type = nesting_type
|
|
163
181
|
|
|
164
182
|
# Event-driven state tracking for when the executor is done
|
|
165
183
|
self._completion_event = threading.Event()
|
|
166
184
|
self._suspend_exception: SuspendExecution | None = None
|
|
185
|
+
self._resume_error: Exception | None = None
|
|
167
186
|
|
|
168
187
|
# ExecutionCounters will keep track of completion criteria and on-going counters
|
|
169
188
|
min_successful = self.completion_config.min_successful or len(self.executables)
|
|
@@ -189,6 +208,14 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
189
208
|
"""Execute a single executable in a child context and return the result."""
|
|
190
209
|
raise NotImplementedError
|
|
191
210
|
|
|
211
|
+
def get_iteration_name(self, index: int) -> str:
|
|
212
|
+
"""Get the display name for an iteration/branch at the given index.
|
|
213
|
+
|
|
214
|
+
Subclasses can override this to provide custom naming (e.g., from item_namer
|
|
215
|
+
or branch names). The default returns "{name_prefix}{index}".
|
|
216
|
+
"""
|
|
217
|
+
return f"{self.name_prefix}{index}"
|
|
218
|
+
|
|
192
219
|
def execute(
|
|
193
220
|
self, execution_state: ExecutionState, executor_context: DurableContext
|
|
194
221
|
) -> BatchResult[ResultType]:
|
|
@@ -209,11 +236,32 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
209
236
|
]
|
|
210
237
|
self._completion_event.clear()
|
|
211
238
|
self._suspend_exception = None
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
239
|
+
self._resume_error = None
|
|
240
|
+
|
|
241
|
+
def resubmitter(ready: list[ExecutableWithState]) -> None:
|
|
242
|
+
"""Resubmit a wave of timed-suspended tasks.
|
|
243
|
+
|
|
244
|
+
One checkpoint refresh serves the whole due wave: the fetch returns
|
|
245
|
+
all operations, so every resumed branch reads fresh state. The
|
|
246
|
+
refresh only raises when the background checkpoint subsystem has
|
|
247
|
+
failed, which is terminal for the whole execution, so record the
|
|
248
|
+
error and wake the parent to re-raise it. Catching here keeps the
|
|
249
|
+
single timer thread alive so a failure does not strand the other
|
|
250
|
+
pending resumes.
|
|
251
|
+
"""
|
|
252
|
+
try:
|
|
253
|
+
execution_state.create_checkpoint()
|
|
254
|
+
except Exception as exc: # noqa: BLE001
|
|
255
|
+
# resubmitter runs only on the single timer thread, so this
|
|
256
|
+
# check-then-set needs no lock. First error wins: keep the
|
|
257
|
+
# earliest failure if several waves fail before execute() reads
|
|
258
|
+
# it (they are the same terminal checkpoint failure anyway).
|
|
259
|
+
if self._resume_error is None: # pragma: no branch
|
|
260
|
+
self._resume_error = exc
|
|
261
|
+
self._completion_event.set()
|
|
262
|
+
return
|
|
263
|
+
for executable_with_state in ready:
|
|
264
|
+
submit_task(executable_with_state)
|
|
217
265
|
|
|
218
266
|
thread_executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
219
267
|
try:
|
|
@@ -246,6 +294,12 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
246
294
|
for future in futures:
|
|
247
295
|
future.cancel()
|
|
248
296
|
|
|
297
|
+
# A timed resume failed to refresh state (terminal checkpoint
|
|
298
|
+
# subsystem failure). Re-raise so the invocation fails and the
|
|
299
|
+
# backend retries from the last durable checkpoint.
|
|
300
|
+
if self._resume_error is not None:
|
|
301
|
+
raise self._resume_error
|
|
302
|
+
|
|
249
303
|
# Suspend execution if everything done and at least one of the tasks raised a suspend exception.
|
|
250
304
|
if self._suspend_exception:
|
|
251
305
|
raise self._suspend_exception
|
|
@@ -391,29 +445,37 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
391
445
|
"""
|
|
392
446
|
Execute a single item in a derived child context.
|
|
393
447
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
directly. This avoids the hidden mutation of the context's
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
448
|
+
Instead of relying on `executor_context.run_in_child_context` we
|
|
449
|
+
generate an operation_id for the child, then call `child_handler`
|
|
450
|
+
directly. This avoids the hidden mutation of the context's
|
|
451
|
+
internal counter. We explicitly derive the child's operation_id
|
|
452
|
+
from `executable.index` so that the same input always produces
|
|
453
|
+
the same id regardless of the order branches actually run in.
|
|
400
454
|
|
|
401
|
-
|
|
402
|
-
|
|
455
|
+
Invariant: `operation_id` for a given executable is deterministic
|
|
456
|
+
and execution-order invariant.
|
|
403
457
|
"""
|
|
404
458
|
|
|
405
|
-
operation_id = executor_context._create_step_id_for_logical_step( # noqa: SLF001
|
|
459
|
+
operation_id: str = executor_context._create_step_id_for_logical_step( # noqa: SLF001
|
|
406
460
|
executable.index
|
|
407
461
|
)
|
|
408
|
-
name =
|
|
409
|
-
|
|
462
|
+
name: str = self.get_iteration_name(executable.index)
|
|
463
|
+
is_virtual: bool = self.nesting_type is NestingType.FLAT
|
|
464
|
+
|
|
465
|
+
child_context: DurableContext = executor_context.create_child_context(
|
|
466
|
+
operation_id, is_virtual=is_virtual
|
|
467
|
+
)
|
|
468
|
+
# For NESTED this is for branch's START/SUCCEED/FAIL checkpoints (not the children of the branch).
|
|
469
|
+
# For FLAT `child_handler` skips checkpoints, so not used.
|
|
470
|
+
# Construct it unconditionally to keep the call simple.
|
|
410
471
|
operation_identifier = OperationIdentifier(
|
|
411
|
-
operation_id,
|
|
412
|
-
|
|
413
|
-
|
|
472
|
+
operation_id=operation_id,
|
|
473
|
+
sub_type=self.sub_type_iteration,
|
|
474
|
+
parent_id=executor_context._parent_id, # noqa: SLF001
|
|
475
|
+
name=name,
|
|
414
476
|
)
|
|
415
477
|
|
|
416
|
-
def run_in_child_handler():
|
|
478
|
+
def run_in_child_handler() -> ResultType:
|
|
417
479
|
return self.execute_item(child_context, executable)
|
|
418
480
|
|
|
419
481
|
result: ResultType = child_handler(
|
|
@@ -424,6 +486,7 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
|
|
|
424
486
|
serdes=self.item_serdes or self.serdes,
|
|
425
487
|
sub_type=self.sub_type_iteration,
|
|
426
488
|
summary_generator=self.summary_generator,
|
|
489
|
+
is_virtual=is_virtual,
|
|
427
490
|
),
|
|
428
491
|
)
|
|
429
492
|
child_context.state.track_replay(operation_id=operation_id)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import math
|
|
5
6
|
import random
|
|
6
7
|
from dataclasses import dataclass, field
|
|
7
8
|
from enum import Enum, StrEnum
|
|
@@ -9,6 +10,7 @@ from typing import TYPE_CHECKING, Generic, TypeVar
|
|
|
9
10
|
|
|
10
11
|
from aws_durable_execution_sdk_python.exceptions import ValidationError
|
|
11
12
|
|
|
13
|
+
|
|
12
14
|
P = TypeVar("P") # Payload type
|
|
13
15
|
R = TypeVar("R") # Result type
|
|
14
16
|
T = TypeVar("T")
|
|
@@ -76,6 +78,42 @@ class TerminationMode(Enum):
|
|
|
76
78
|
ABANDON = "ABANDON"
|
|
77
79
|
|
|
78
80
|
|
|
81
|
+
class NestingType(Enum):
|
|
82
|
+
"""Control how child contexts are created for batch operations.
|
|
83
|
+
|
|
84
|
+
Applies to `map` and `parallel`. Each branch or iteration runs inside a
|
|
85
|
+
child context.
|
|
86
|
+
|
|
87
|
+
- NESTED: full checkpointed context
|
|
88
|
+
- FLAT: a virtual context that skips checkpoints for the branch/iteration.
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
NESTED = "NESTED"
|
|
93
|
+
"""Create CONTEXT operations for each branch/iteration with full checkpointing.
|
|
94
|
+
|
|
95
|
+
Operations within each branch/iteration are wrapped in their own context.
|
|
96
|
+
|
|
97
|
+
- Observability: high — each branch/iteration appears as a separate
|
|
98
|
+
operation in execution history.
|
|
99
|
+
- Cost: higher — consumes more operations due to CONTEXT creation
|
|
100
|
+
overhead.
|
|
101
|
+
- Scale: lower maximum iterations due to operation limits.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
FLAT = "FLAT"
|
|
105
|
+
"""Skip CONTEXT operations for branches/iterations using virtual contexts.
|
|
106
|
+
|
|
107
|
+
Operations execute directly without individual context wrapping.
|
|
108
|
+
|
|
109
|
+
- Observability: lower — branches/iterations don't appear as separate
|
|
110
|
+
operations in execution history.
|
|
111
|
+
- Cost: ~30% lower — reduces operation consumption by skipping CONTEXT
|
|
112
|
+
overhead.
|
|
113
|
+
- Scale: higher maximum iterations possible within operation limits.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
|
|
79
117
|
@dataclass(frozen=True)
|
|
80
118
|
class CompletionConfig:
|
|
81
119
|
"""Configuration for determining when parallel/map operations complete.
|
|
@@ -187,6 +225,10 @@ class ParallelConfig:
|
|
|
187
225
|
Used internally by map/parallel operations to handle large BatchResult payloads.
|
|
188
226
|
Signature: (result: T) -> str
|
|
189
227
|
|
|
228
|
+
nesting_type: How child operations should inherit context from their parent.
|
|
229
|
+
- NESTED: Each branch runs in its own isolated context (default)
|
|
230
|
+
- FLAT: All branches share the same parent context
|
|
231
|
+
|
|
190
232
|
Example:
|
|
191
233
|
# Run at most 3 branches concurrently, succeed if any one succeeds
|
|
192
234
|
config = ParallelConfig(
|
|
@@ -202,6 +244,42 @@ class ParallelConfig:
|
|
|
202
244
|
serdes: SerDes | None = None
|
|
203
245
|
item_serdes: SerDes | None = None
|
|
204
246
|
summary_generator: SummaryGenerator | None = None
|
|
247
|
+
nesting_type: NestingType = NestingType.NESTED
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@dataclass(frozen=True)
|
|
251
|
+
class ParallelBranch(Generic[T]):
|
|
252
|
+
"""A named branch for parallel execution.
|
|
253
|
+
|
|
254
|
+
Use this to provide custom names for parallel branches, improving
|
|
255
|
+
observability in execution history.
|
|
256
|
+
|
|
257
|
+
Type Parameters:
|
|
258
|
+
T: The return type of the branch function.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
func: The callable to execute in this branch. Receives a DurableContext.
|
|
262
|
+
name: Optional custom name for this branch. When provided, replaces
|
|
263
|
+
the default "parallel-branch-{index}" naming in execution history.
|
|
264
|
+
This affects observability but not replay determinism.
|
|
265
|
+
|
|
266
|
+
Example:
|
|
267
|
+
context.parallel(
|
|
268
|
+
functions=[
|
|
269
|
+
ParallelBranch(func=lambda ctx: fetch_user(ctx), name="fetch-user-data"),
|
|
270
|
+
ParallelBranch(func=lambda ctx: fetch_orders(ctx), name="fetch-order-history"),
|
|
271
|
+
],
|
|
272
|
+
name="load-data",
|
|
273
|
+
config=ParallelConfig(max_concurrency=2),
|
|
274
|
+
)
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
func: Callable
|
|
278
|
+
name: str | None = None
|
|
279
|
+
|
|
280
|
+
def __call__(self, *args, **kwargs):
|
|
281
|
+
"""Delegate to the wrapped function, making ParallelBranch itself callable."""
|
|
282
|
+
return self.func(*args, **kwargs)
|
|
205
283
|
|
|
206
284
|
|
|
207
285
|
class StepSemantics(Enum):
|
|
@@ -218,12 +296,6 @@ class StepConfig:
|
|
|
218
296
|
serdes: SerDes | None = None
|
|
219
297
|
|
|
220
298
|
|
|
221
|
-
class CheckpointMode(Enum):
|
|
222
|
-
NO_CHECKPOINT = ("NO_CHECKPOINT",)
|
|
223
|
-
CHECKPOINT_AT_FINISH = ("CHECKPOINT_AT_FINISH",)
|
|
224
|
-
CHECKPOINT_AT_START_AND_FINISH = "CHECKPOINT_AT_START_AND_FINISH"
|
|
225
|
-
|
|
226
|
-
|
|
227
299
|
@dataclass(frozen=True)
|
|
228
300
|
class ChildConfig(Generic[T]):
|
|
229
301
|
"""Configuration options for child context operations.
|
|
@@ -259,21 +331,23 @@ class ChildConfig(Generic[T]):
|
|
|
259
331
|
|
|
260
332
|
Used internally by map/parallel operations to handle large BatchResult payloads.
|
|
261
333
|
Signature: (result: T) -> str
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
334
|
+
|
|
335
|
+
is_virtual: When True, skip all checkpoints (START, SUCCEED,
|
|
336
|
+
FAIL) for this child context and propagate the caller's reporting
|
|
337
|
+
parent id through to operations created inside the child. The
|
|
338
|
+
branch is a logical scope for step-id prefixing but does not
|
|
339
|
+
appear in the execution history. Used internally by
|
|
340
|
+
NestingType.FLAT branches. Use this to group operations without
|
|
341
|
+
adding a CONTEXT entry to the execution history.
|
|
268
342
|
|
|
269
343
|
See TypeScript reference: aws-durable-execution-sdk-js/src/types/index.ts
|
|
270
344
|
"""
|
|
271
345
|
|
|
272
|
-
# checkpoint_mode: CheckpointMode = CheckpointMode.CHECKPOINT_AT_START_AND_FINISH
|
|
273
346
|
serdes: SerDes | None = None
|
|
274
347
|
item_serdes: SerDes | None = None
|
|
275
348
|
sub_type: OperationSubType | None = None
|
|
276
349
|
summary_generator: SummaryGenerator | None = None
|
|
350
|
+
is_virtual: bool = False
|
|
277
351
|
|
|
278
352
|
|
|
279
353
|
class ItemsPerBatchUnit(Enum):
|
|
@@ -317,12 +391,15 @@ class ItemBatcher(Generic[T]):
|
|
|
317
391
|
|
|
318
392
|
|
|
319
393
|
@dataclass(frozen=True)
|
|
320
|
-
class MapConfig:
|
|
394
|
+
class MapConfig(Generic[T]):
|
|
321
395
|
"""Configuration options for map operations over collections.
|
|
322
396
|
|
|
323
397
|
This class configures how map operations process collections of items,
|
|
324
398
|
including concurrency, batching, completion criteria, and serialization.
|
|
325
399
|
|
|
400
|
+
Type Parameters:
|
|
401
|
+
T: The type of items being processed in the map operation.
|
|
402
|
+
|
|
326
403
|
Args:
|
|
327
404
|
max_concurrency: Maximum number of items to process concurrently.
|
|
328
405
|
If None, no limit is imposed and all items are processed concurrently.
|
|
@@ -361,6 +438,16 @@ class MapConfig:
|
|
|
361
438
|
Used internally by map/parallel operations to handle large BatchResult payloads.
|
|
362
439
|
Signature: (result: T) -> str
|
|
363
440
|
|
|
441
|
+
nesting_type: How child operations should inherit context from their parent.
|
|
442
|
+
- NESTED: Each item runs in its own isolated context (default)
|
|
443
|
+
- FLAT: All items share the same parent context
|
|
444
|
+
|
|
445
|
+
item_namer: Optional callable to generate custom names for each map iteration.
|
|
446
|
+
When provided, replaces the default "map-item-{index}" naming scheme.
|
|
447
|
+
Receives the item and its index, and returns a string name for that iteration.
|
|
448
|
+
This affects observability (execution history names) but not replay determinism.
|
|
449
|
+
If None, uses the default naming: "map-item-{index}".
|
|
450
|
+
|
|
364
451
|
Example:
|
|
365
452
|
# Process 5 items at a time, batch by count, require all to succeed
|
|
366
453
|
config = MapConfig(
|
|
@@ -368,6 +455,12 @@ class MapConfig:
|
|
|
368
455
|
item_batcher=ItemBatcher(max_items_per_batch=10),
|
|
369
456
|
completion_config=CompletionConfig.all_successful()
|
|
370
457
|
)
|
|
458
|
+
|
|
459
|
+
# With custom iteration names
|
|
460
|
+
config = MapConfig(
|
|
461
|
+
max_concurrency=5,
|
|
462
|
+
item_namer=lambda item, index: f"process-order-{item.id}"
|
|
463
|
+
)
|
|
371
464
|
"""
|
|
372
465
|
|
|
373
466
|
max_concurrency: int | None = None
|
|
@@ -376,6 +469,8 @@ class MapConfig:
|
|
|
376
469
|
serdes: SerDes | None = None
|
|
377
470
|
item_serdes: SerDes | None = None
|
|
378
471
|
summary_generator: SummaryGenerator | None = None
|
|
472
|
+
nesting_type: NestingType = NestingType.NESTED
|
|
473
|
+
item_namer: Callable[[T, int], str] | None = None
|
|
379
474
|
|
|
380
475
|
|
|
381
476
|
@dataclass(frozen=True)
|
|
@@ -495,5 +590,16 @@ class JitterStrategy(StrEnum):
|
|
|
495
590
|
# Full jitter: random(0, delay)
|
|
496
591
|
return random.random() * delay # noqa: S311
|
|
497
592
|
|
|
593
|
+
def finalize_delay(self, base_delay: float) -> int:
|
|
594
|
+
"""Apply jitter, round up, and clamp to a minimum of 1 second.
|
|
595
|
+
|
|
596
|
+
Args:
|
|
597
|
+
base_delay: The base delay value before jitter is applied
|
|
598
|
+
|
|
599
|
+
Returns:
|
|
600
|
+
The final delay in whole seconds, at least 1
|
|
601
|
+
"""
|
|
602
|
+
return max(1, math.ceil(self.apply_jitter(base_delay)))
|
|
603
|
+
|
|
498
604
|
|
|
499
605
|
# endregion Jitter
|