async-lambda-unstable 0.5.7__tar.gz → 0.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.
- async_lambda_unstable-0.6.0/.gitignore +164 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/PKG-INFO +7 -3
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/__init__.py +1 -1
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/build_config.py +5 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/controller.py +59 -2
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/pyproject.toml +24 -5
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/PKG-INFO +0 -438
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/SOURCES.txt +0 -34
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/dependency_links.txt +0 -1
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/entry_points.txt +0 -2
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/requires.txt +0 -6
- async-lambda-unstable-0.5.7/async_lambda_unstable.egg-info/top_level.txt +0 -1
- async-lambda-unstable-0.5.7/setup.cfg +0 -4
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/README.md +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/cli.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/client.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/config.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/defer.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/env.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/middleware.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/__init__.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/api_response.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/case_insensitive_dict.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/__init__.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/api_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/base_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/dynamodb_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/managed_sqs_batch_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/managed_sqs_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/scheduled_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/unmanaged_sqs_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/mock/mock_context.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/mock/mock_event.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/task.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/payload_encoder.py +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/py.typed +0 -0
- {async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/util.py +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
*samconfig.toml
|
|
2
|
+
|
|
3
|
+
# Byte-compiled / optimized / DLL files
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
share/python-wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
MANIFEST
|
|
30
|
+
|
|
31
|
+
# PyInstaller
|
|
32
|
+
# Usually these files are written by a python script from a template
|
|
33
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
34
|
+
*.manifest
|
|
35
|
+
*.spec
|
|
36
|
+
|
|
37
|
+
# Installer logs
|
|
38
|
+
pip-log.txt
|
|
39
|
+
pip-delete-this-directory.txt
|
|
40
|
+
|
|
41
|
+
# Unit test / coverage reports
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.nox/
|
|
45
|
+
.coverage
|
|
46
|
+
.coverage.*
|
|
47
|
+
.cache
|
|
48
|
+
nosetests.xml
|
|
49
|
+
coverage.xml
|
|
50
|
+
*.cover
|
|
51
|
+
*.py,cover
|
|
52
|
+
.hypothesis/
|
|
53
|
+
.pytest_cache/
|
|
54
|
+
cover/
|
|
55
|
+
|
|
56
|
+
# Translations
|
|
57
|
+
*.mo
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Django stuff:
|
|
61
|
+
*.log
|
|
62
|
+
local_settings.py
|
|
63
|
+
db.sqlite3
|
|
64
|
+
db.sqlite3-journal
|
|
65
|
+
|
|
66
|
+
# Flask stuff:
|
|
67
|
+
instance/
|
|
68
|
+
.webassets-cache
|
|
69
|
+
|
|
70
|
+
# Scrapy stuff:
|
|
71
|
+
.scrapy
|
|
72
|
+
|
|
73
|
+
# Sphinx documentation
|
|
74
|
+
docs/_build/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
.pybuilder/
|
|
78
|
+
target/
|
|
79
|
+
|
|
80
|
+
# Jupyter Notebook
|
|
81
|
+
.ipynb_checkpoints
|
|
82
|
+
|
|
83
|
+
# IPython
|
|
84
|
+
profile_default/
|
|
85
|
+
ipython_config.py
|
|
86
|
+
|
|
87
|
+
# pyenv
|
|
88
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
89
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
90
|
+
# .python-version
|
|
91
|
+
|
|
92
|
+
# pipenv
|
|
93
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
94
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
95
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
96
|
+
# install all needed dependencies.
|
|
97
|
+
#Pipfile.lock
|
|
98
|
+
|
|
99
|
+
# poetry
|
|
100
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
101
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
102
|
+
# commonly ignored for libraries.
|
|
103
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
104
|
+
#poetry.lock
|
|
105
|
+
|
|
106
|
+
# pdm
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
108
|
+
#pdm.lock
|
|
109
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
110
|
+
# in version control.
|
|
111
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
112
|
+
.pdm.toml
|
|
113
|
+
|
|
114
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
115
|
+
__pypackages__/
|
|
116
|
+
|
|
117
|
+
# Celery stuff
|
|
118
|
+
celerybeat-schedule
|
|
119
|
+
celerybeat.pid
|
|
120
|
+
|
|
121
|
+
# SageMath parsed files
|
|
122
|
+
*.sage.py
|
|
123
|
+
|
|
124
|
+
# Environments
|
|
125
|
+
.env
|
|
126
|
+
.venv
|
|
127
|
+
env/
|
|
128
|
+
venv/
|
|
129
|
+
ENV/
|
|
130
|
+
env.bak/
|
|
131
|
+
venv.bak/
|
|
132
|
+
|
|
133
|
+
# Spyder project settings
|
|
134
|
+
.spyderproject
|
|
135
|
+
.spyproject
|
|
136
|
+
|
|
137
|
+
# Rope project settings
|
|
138
|
+
.ropeproject
|
|
139
|
+
|
|
140
|
+
# mkdocs documentation
|
|
141
|
+
/site
|
|
142
|
+
|
|
143
|
+
# mypy
|
|
144
|
+
.mypy_cache/
|
|
145
|
+
.dmypy.json
|
|
146
|
+
dmypy.json
|
|
147
|
+
|
|
148
|
+
# Pyre type checker
|
|
149
|
+
.pyre/
|
|
150
|
+
|
|
151
|
+
# pytype static type analyzer
|
|
152
|
+
.pytype/
|
|
153
|
+
|
|
154
|
+
# Cython debug symbols
|
|
155
|
+
cython_debug/
|
|
156
|
+
|
|
157
|
+
# PyCharm
|
|
158
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
159
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
160
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
161
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
162
|
+
#.idea/
|
|
163
|
+
*.DS_Store
|
|
164
|
+
uv.lock
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: async-lambda-unstable
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A framework for creating AWS Lambda Async Workflows. - Unstable Branch
|
|
5
5
|
Author-email: "Nuclei, Inc" <engineering@nuclei.ai>
|
|
6
|
-
|
|
6
|
+
Requires-Dist: click>=8.0.0
|
|
7
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
7
8
|
Provides-Extra: local
|
|
9
|
+
Requires-Dist: boto3; extra == 'local'
|
|
10
|
+
Requires-Dist: flask<3.0.0,>=2.3.0; extra == 'local'
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
8
12
|
|
|
9
13
|
# async-lambda
|
|
10
14
|
|
|
@@ -21,4 +21,4 @@ from .models.events.managed_sqs_event import ManagedSQSEvent as ManagedSQSEvent
|
|
|
21
21
|
from .models.events.scheduled_event import ScheduledEvent as ScheduledEvent
|
|
22
22
|
from .models.events.unmanaged_sqs_event import UnmanagedSQSEvent as UnmanagedSQSEvent
|
|
23
23
|
|
|
24
|
-
__version__ = "0.
|
|
24
|
+
__version__ = "0.6.0"
|
|
@@ -33,6 +33,7 @@ class AsyncLambdaBuildConfig:
|
|
|
33
33
|
tls_version (Optional[str]): TLS version to use for the API.
|
|
34
34
|
certificate_arn (Optional[str]): ARN of the SSL certificate for the domain.
|
|
35
35
|
hosted_zone_id (Optional[str]): Hosted zone name for the Lambda/API.
|
|
36
|
+
auto_create_acm_certificate (bool): Whether or not to auto create a certificate in ACM for the domain name. Must be used in conjunction with hosted_zone_id and domain_name to be used.
|
|
36
37
|
|
|
37
38
|
Methods:
|
|
38
39
|
new(config: dict) -> AsyncLambdaBuildConfig:
|
|
@@ -55,6 +56,7 @@ class AsyncLambdaBuildConfig:
|
|
|
55
56
|
tls_version: Optional[str] = None
|
|
56
57
|
certificate_arn: Optional[str] = None
|
|
57
58
|
hosted_zone_id: Optional[str] = None
|
|
59
|
+
auto_create_acm_certificate: Optional[bool] = None
|
|
58
60
|
|
|
59
61
|
@classmethod
|
|
60
62
|
def new(cls, config: dict) -> "AsyncLambdaBuildConfig":
|
|
@@ -94,6 +96,7 @@ class AsyncLambdaBuildConfig:
|
|
|
94
96
|
tls_version=config.get("tls_version"),
|
|
95
97
|
certificate_arn=config.get("certificate_arn"),
|
|
96
98
|
hosted_zone_id=config.get("hosted_zone_id"),
|
|
99
|
+
auto_create_acm_certificate=config.get("auto_create_acm_certificate"),
|
|
97
100
|
)
|
|
98
101
|
|
|
99
102
|
def merge(self, other: "AsyncLambdaBuildConfig"):
|
|
@@ -113,6 +116,8 @@ class AsyncLambdaBuildConfig:
|
|
|
113
116
|
self.certificate_arn = other.certificate_arn
|
|
114
117
|
if other.hosted_zone_id is not None:
|
|
115
118
|
self.hosted_zone_id = other.hosted_zone_id
|
|
119
|
+
if other.auto_create_acm_certificate is not None:
|
|
120
|
+
self.auto_create_acm_certificate = other.auto_create_acm_certificate
|
|
116
121
|
|
|
117
122
|
|
|
118
123
|
def get_build_config_for_stage(
|
|
@@ -137,6 +137,7 @@ class AsyncLambdaController:
|
|
|
137
137
|
current_task_id: Optional[str] = None
|
|
138
138
|
current_lane: Optional[int] = None
|
|
139
139
|
current_invocation_id: Optional[str] = None
|
|
140
|
+
_current_event_context: Optional[Any] = None
|
|
140
141
|
parent_controller: Optional["AsyncLambdaController"] = None
|
|
141
142
|
middleware: List[MiddlewareRegistration]
|
|
142
143
|
delete_s3_payloads: bool = False
|
|
@@ -398,9 +399,10 @@ class AsyncLambdaController:
|
|
|
398
399
|
if len(build_config.method_settings) > 0:
|
|
399
400
|
properties["MethodSettings"] = build_config.method_settings
|
|
400
401
|
if build_config.domain_name is not None:
|
|
401
|
-
|
|
402
|
+
domain_dict: dict = {
|
|
402
403
|
"DomainName": build_config.domain_name,
|
|
403
404
|
}
|
|
405
|
+
properties["Domain"] = domain_dict
|
|
404
406
|
if build_config.certificate_arn is not None:
|
|
405
407
|
properties["Domain"][
|
|
406
408
|
"CertificateArn"
|
|
@@ -409,10 +411,35 @@ class AsyncLambdaController:
|
|
|
409
411
|
properties["Domain"][
|
|
410
412
|
"SecurityPolicy"
|
|
411
413
|
] = build_config.tls_version
|
|
414
|
+
elif (
|
|
415
|
+
build_config.auto_create_acm_certificate is True
|
|
416
|
+
and build_config.hosted_zone_id is not None
|
|
417
|
+
):
|
|
418
|
+
template["Resources"]["AsyncLambdaAPICertificate"] = {
|
|
419
|
+
"Type": "AWS::CertificateManager::Certificate",
|
|
420
|
+
"Properties": {
|
|
421
|
+
"DomainName": build_config.domain_name,
|
|
422
|
+
"ValidationMethod": "DNS",
|
|
423
|
+
"DomainValidationOptions": [
|
|
424
|
+
{
|
|
425
|
+
"DomainName": build_config.domain_name,
|
|
426
|
+
"HostedZoneId": build_config.hosted_zone_id,
|
|
427
|
+
}
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
}
|
|
431
|
+
properties["Domain"]["CertificateArn"] = {
|
|
432
|
+
"Ref": "AsyncLambdaAPICertificate"
|
|
433
|
+
}
|
|
434
|
+
if build_config.tls_version is not None:
|
|
435
|
+
properties["Domain"][
|
|
436
|
+
"SecurityPolicy"
|
|
437
|
+
] = build_config.tls_version
|
|
412
438
|
if build_config.hosted_zone_id is not None:
|
|
413
|
-
properties["Domain"]["Route53"] = {
|
|
439
|
+
properties["Domain"]["Route53"] = {
|
|
414
440
|
"HostedZoneId": build_config.hosted_zone_id
|
|
415
441
|
}
|
|
442
|
+
|
|
416
443
|
template["Resources"]["AsyncLambdaAPIGateway"] = {
|
|
417
444
|
"Type": "AWS::Serverless::Api",
|
|
418
445
|
"Properties": properties,
|
|
@@ -497,6 +524,23 @@ class AsyncLambdaController:
|
|
|
497
524
|
self.parent_controller.set_current_invocation_id(invocation_id)
|
|
498
525
|
self.current_invocation_id = invocation_id
|
|
499
526
|
|
|
527
|
+
def set_current_event_context(self, context: Any):
|
|
528
|
+
"""
|
|
529
|
+
Set the current event context on the parent controller.
|
|
530
|
+
"""
|
|
531
|
+
if self.parent_controller is not None:
|
|
532
|
+
self.parent_controller.set_current_event_context(context)
|
|
533
|
+
return
|
|
534
|
+
self._current_event_context = context
|
|
535
|
+
|
|
536
|
+
def get_current_event_context(self) -> Any:
|
|
537
|
+
"""
|
|
538
|
+
Get the current event context
|
|
539
|
+
"""
|
|
540
|
+
if self.parent_controller is not None:
|
|
541
|
+
return self.parent_controller.get_current_event_context()
|
|
542
|
+
return self._current_event_context
|
|
543
|
+
|
|
500
544
|
def handle_invocation(self, event, context, task_id: Optional[str] = None):
|
|
501
545
|
"""
|
|
502
546
|
Handles the invocation of a task based on its trigger type.
|
|
@@ -525,6 +569,8 @@ class AsyncLambdaController:
|
|
|
525
569
|
|
|
526
570
|
args = (event, context, task)
|
|
527
571
|
|
|
572
|
+
self.set_current_event_context(context)
|
|
573
|
+
|
|
528
574
|
if task.trigger_type == TaskTriggerType.MANAGED_SQS:
|
|
529
575
|
_event = ManagedSQSEvent(*args)
|
|
530
576
|
lane_count = task.get_lane_count()
|
|
@@ -591,6 +637,7 @@ class AsyncLambdaController:
|
|
|
591
637
|
delay: int = 0,
|
|
592
638
|
force_sync: bool = False,
|
|
593
639
|
lane: Optional[int] = None,
|
|
640
|
+
message_group_id: Optional[str] = None,
|
|
594
641
|
):
|
|
595
642
|
"""
|
|
596
643
|
Sends an asynchronous invocation payload to a managed or external task via SQS.
|
|
@@ -621,6 +668,7 @@ class AsyncLambdaController:
|
|
|
621
668
|
delay=delay,
|
|
622
669
|
force_sync=force_sync,
|
|
623
670
|
lane=lane,
|
|
671
|
+
message_group_id=message_group_id,
|
|
624
672
|
)
|
|
625
673
|
is_external_task = False
|
|
626
674
|
if destination_task_id not in self.tasks:
|
|
@@ -667,6 +715,7 @@ class AsyncLambdaController:
|
|
|
667
715
|
# Sync invocation with mock event/context
|
|
668
716
|
current_task_id = self.current_task_id
|
|
669
717
|
current_lane = self.get_current_lane()
|
|
718
|
+
current_context = self.get_current_event_context()
|
|
670
719
|
queue_arn = destination_task.get_managed_queue_arn(lane=lane)
|
|
671
720
|
mock_event = MockSQSLambdaEvent(
|
|
672
721
|
json.dumps(sqs_payload), source_queue_arn=queue_arn
|
|
@@ -677,6 +726,7 @@ class AsyncLambdaController:
|
|
|
677
726
|
)
|
|
678
727
|
self.set_current_task_id(current_task_id)
|
|
679
728
|
self.set_current_lane(current_lane)
|
|
729
|
+
self.set_current_event_context(current_context)
|
|
680
730
|
return result
|
|
681
731
|
else:
|
|
682
732
|
if is_external_task:
|
|
@@ -684,10 +734,15 @@ class AsyncLambdaController:
|
|
|
684
734
|
else:
|
|
685
735
|
assert destination_task is not None
|
|
686
736
|
url = destination_task.get_managed_queue_url(lane=lane)
|
|
737
|
+
|
|
738
|
+
_kwargs = {}
|
|
739
|
+
if message_group_id is not None:
|
|
740
|
+
_kwargs["MessageGroupId"] = message_group_id
|
|
687
741
|
get_sqs_client().send_message(
|
|
688
742
|
QueueUrl=url,
|
|
689
743
|
MessageBody=json.dumps(sqs_payload),
|
|
690
744
|
DelaySeconds=delay,
|
|
745
|
+
**_kwargs,
|
|
691
746
|
)
|
|
692
747
|
|
|
693
748
|
def send_async_invoke_payload_batch(
|
|
@@ -932,6 +987,7 @@ class AsyncLambdaController:
|
|
|
932
987
|
delay: int = 0,
|
|
933
988
|
force_sync: bool = False,
|
|
934
989
|
lane: Optional[int] = None,
|
|
990
|
+
message_group_id: Optional[str] = None,
|
|
935
991
|
):
|
|
936
992
|
"""
|
|
937
993
|
Asynchronously invokes a task by sending a payload to the specified destination.
|
|
@@ -960,6 +1016,7 @@ class AsyncLambdaController:
|
|
|
960
1016
|
delay=delay,
|
|
961
1017
|
force_sync=force_sync,
|
|
962
1018
|
lane=lane,
|
|
1019
|
+
message_group_id=message_group_id,
|
|
963
1020
|
)
|
|
964
1021
|
|
|
965
1022
|
def async_invoke_batch(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
3
4
|
|
|
4
5
|
[project]
|
|
5
6
|
name = "async-lambda-unstable"
|
|
@@ -15,11 +16,29 @@ local = ["boto3", "flask>=2.3.0,<3.0.0"]
|
|
|
15
16
|
[project.scripts]
|
|
16
17
|
async-lambda = "async_lambda.cli:cli"
|
|
17
18
|
|
|
18
|
-
[tool.
|
|
19
|
-
|
|
19
|
+
[tool.hatch.version]
|
|
20
|
+
path = "async_lambda/__init__.py"
|
|
21
|
+
|
|
22
|
+
[tool.hatch.build.targets.wheel]
|
|
23
|
+
packages = ["async_lambda"]
|
|
24
|
+
|
|
25
|
+
[tool.hatch.build.targets.sdist]
|
|
26
|
+
include = [
|
|
27
|
+
"async_lambda/**",
|
|
28
|
+
"pyproject.toml",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
]
|
|
32
|
+
# (optional) extra excludes for safety
|
|
33
|
+
exclude = [
|
|
34
|
+
"tests/**",
|
|
35
|
+
".github/**",
|
|
36
|
+
"docs/**",
|
|
37
|
+
"examples/**",
|
|
38
|
+
"scripts/**",
|
|
39
|
+
"*.ipynb",
|
|
40
|
+
]
|
|
20
41
|
|
|
21
|
-
[tool.setuptools.package-data]
|
|
22
|
-
"async_lambda" = ["py.typed"]
|
|
23
42
|
|
|
24
43
|
[tool.pytest.ini_options]
|
|
25
44
|
minversion = "6.0"
|
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: async-lambda-unstable
|
|
3
|
-
Version: 0.5.7
|
|
4
|
-
Summary: A framework for creating AWS Lambda Async Workflows. - Unstable Branch
|
|
5
|
-
Author-email: "Nuclei, Inc" <engineering@nuclei.ai>
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Provides-Extra: local
|
|
8
|
-
|
|
9
|
-
# async-lambda
|
|
10
|
-
|
|
11
|
-
Async-lambda is a Python framework for building scalable, event-driven AWS Lambda applications with first-class support for asynchronous invocation via SQS queues. It provides a high-level abstraction for orchestrating Lambda functions, managing event triggers, and handling complex workflows with minimal boilerplate.
|
|
12
|
-
|
|
13
|
-
`async-lambda` converts your application into a `Serverless Application Model (SAM)`
|
|
14
|
-
template which can be deployed with the `SAM` cli tool or via Cloudformation.
|
|
15
|
-
|
|
16
|
-
## Features
|
|
17
|
-
|
|
18
|
-
- **Async Task Abstraction**: Define tasks as Lambda functions triggered by SQS, API Gateway, DynamoDB Streams, or scheduled events.
|
|
19
|
-
- **Automatic SAM Template Generation**: Converts your application into a Serverless Application Model (SAM) template for deployment.
|
|
20
|
-
- **Lane-based Parallelism**: Scale async tasks horizontally using multiple SQS queues (lanes) and control concurrency per lane.
|
|
21
|
-
- **Middleware Support**: Register middleware to wrap task execution, enabling cross-cutting concerns (logging, auth, etc.).
|
|
22
|
-
- **Large Payload Handling**: Offload large payloads to S3 automatically when exceeding SQS size limits.
|
|
23
|
-
- **Dead Letter Queues (DLQ)**: Robust error handling and message redrive for failed async invocations.
|
|
24
|
-
- **Configurable via Code and JSON**: Set configuration at the app, stage, and task level using Python or config files.
|
|
25
|
-
- **Task Initialization**: Run custom logic during Lambda INIT phase for caching, setup, or resource allocation.
|
|
26
|
-
|
|
27
|
-
## Getting Started
|
|
28
|
-
|
|
29
|
-
### Installation
|
|
30
|
-
|
|
31
|
-
Add async-lambda to your project (see requirements in `pyproject.toml`).
|
|
32
|
-
|
|
33
|
-
### Basic Usage
|
|
34
|
-
|
|
35
|
-
```python
|
|
36
|
-
from async_lambda import AsyncLambdaController, config_set_name, ScheduledEvent, ManagedSQSEvent
|
|
37
|
-
|
|
38
|
-
app = AsyncLambdaController()
|
|
39
|
-
config_set_name("project-name")
|
|
40
|
-
lambda_handler = app.async_lambda_handler # Required Lambda export
|
|
41
|
-
|
|
42
|
-
@app.scheduled_task('ScheduledTask1', schedule_expression="rate(15 minutes)")
|
|
43
|
-
def scheduled_task_1(event: ScheduledEvent):
|
|
44
|
-
app.async_invoke("AsyncTask1", payload={"foo": "bar"})
|
|
45
|
-
|
|
46
|
-
@app.async_task('AsyncTask1')
|
|
47
|
-
def async_task_2(event: ManagedSQSEvent):
|
|
48
|
-
print(event.payload) # {"foo": "bar"}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Packaging & Deployment
|
|
52
|
-
|
|
53
|
-
Use the async-lambda CLI to build and package your app:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
async-lambda build app --stage <stage-name>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
This generates a SAM template (`template.json`) and deployment bundle (`deployment.zip`). Deploy using AWS SAM CLI or CloudFormation.
|
|
60
|
-
|
|
61
|
-
## Core Concepts
|
|
62
|
-
|
|
63
|
-
### Controller & Tasks
|
|
64
|
-
|
|
65
|
-
- **AsyncLambdaController**: Central orchestrator for registering tasks, managing middleware, and handling invocations.
|
|
66
|
-
- **Task**: Each task is a Lambda function with a unique `task_id` and a trigger type (SQS, API, DynamoDB, schedule).
|
|
67
|
-
|
|
68
|
-
#### Task Decorators
|
|
69
|
-
|
|
70
|
-
All task decorators accept common configuration arguments:
|
|
71
|
-
- `memory`: Memory allocation (MB)
|
|
72
|
-
- `timeout`: Timeout (seconds)
|
|
73
|
-
- `ephemeral_storage`: Ephemeral storage (MB)
|
|
74
|
-
- `maximum_concurrency`: Max concurrency for SQS triggers (int or list per lane)
|
|
75
|
-
- `lane_count`: Number of parallel lanes (for async tasks)
|
|
76
|
-
- `init_tasks`: Functions to run during Lambda INIT phase
|
|
77
|
-
|
|
78
|
-
#### Example: Async Task
|
|
79
|
-
|
|
80
|
-
```python
|
|
81
|
-
@app.async_task("TaskID")
|
|
82
|
-
def async_task(event: ManagedSQSEvent):
|
|
83
|
-
print(event.payload)
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
**It is quite easy to get into infinite looping situations when utilizing `async-lambda` and care should be taken.**
|
|
88
|
-
|
|
89
|
-
**INFINITE LOOP EXAMPLE**
|
|
90
|
-
|
|
91
|
-
```python
|
|
92
|
-
# If task_1 where to ever get invoked, then it would start an infinite loop with
|
|
93
|
-
# task 1 invoking task 2, task 2 invoking task 1, and repeat...
|
|
94
|
-
|
|
95
|
-
@app.async_task("Task1")
|
|
96
|
-
def task_1(event: ManagedSQSEvent):
|
|
97
|
-
app.async_invoke("Task2", {})
|
|
98
|
-
|
|
99
|
-
@app.async_task("Task2")
|
|
100
|
-
def task_1(event: ManagedSQSEvent):
|
|
101
|
-
app.async_invoke("Task1", {})
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
#### Example: Scheduled Task
|
|
105
|
-
|
|
106
|
-
```python
|
|
107
|
-
@app.scheduled_task("TaskID", schedule_expression='rate(15 minutes)')
|
|
108
|
-
def scheduled_task(event: ScheduledEvent):
|
|
109
|
-
...
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
#### Example: API Task
|
|
113
|
-
|
|
114
|
-
```python
|
|
115
|
-
@app.api_task("TaskID", path='/test', method='get')
|
|
116
|
-
def api_task(event: APIEvent):
|
|
117
|
-
print(event.headers)
|
|
118
|
-
print(event.querystring_params)
|
|
119
|
-
print(event.body)
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
#### Example: Unmanaged SQS Task
|
|
123
|
-
|
|
124
|
-
```python
|
|
125
|
-
@app.sqs_task("TaskID", queue_arn='queue-arn')
|
|
126
|
-
def sqs_task(event: UnmanagedSQSEvent):
|
|
127
|
-
print(event.body)
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Lanes & Concurrency
|
|
131
|
-
|
|
132
|
-
Async tasks can be scaled horizontally using lanes. Each lane is a separate SQS queue and can have its own concurrency limit. Lane assignment can be controlled at the controller, sub-controller, or task level.
|
|
133
|
-
|
|
134
|
-
```python
|
|
135
|
-
app = AsyncLambdaController(lane_count=2)
|
|
136
|
-
|
|
137
|
-
@app.async_task("SwitchBoard")
|
|
138
|
-
def switch_board(event: ManagedSQSEvent):
|
|
139
|
-
lane = 1 if event.payload['value'] > 50000 else 0
|
|
140
|
-
app.async_invoke("ProcessingTask", event.payload, lane=lane)
|
|
141
|
-
|
|
142
|
-
@app.async_task("ProcessingTask", maximum_concurrency=[10, 2])
|
|
143
|
-
def processing_task(event: ManagedSQSEvent):
|
|
144
|
-
...
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Middleware
|
|
148
|
-
|
|
149
|
-
Middleware functions wrap task execution and can be used for logging, authentication, or modifying events/responses.
|
|
150
|
-
|
|
151
|
-
```python
|
|
152
|
-
def async_lambda_middleware(event, call_next):
|
|
153
|
-
print(f"Invocation Payload: {event}")
|
|
154
|
-
result = call_next(event)
|
|
155
|
-
print(f"Invocation Result: {result}")
|
|
156
|
-
return result
|
|
157
|
-
|
|
158
|
-
controller = AsyncLambdaController(middleware=[([BaseEvent], async_lambda_middleware)])
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
If there are multiple middleware functions then `call_next` will actually be calling the next middleware function in the stack.
|
|
162
|
-
|
|
163
|
-
For example if there is middleware functions `A` and `B` registered in that order.
|
|
164
|
-
Then the execution order would go:
|
|
165
|
-
|
|
166
|
-
`A(Pre)` -> `B(Pre)` -> `Task` -> `B(Post)` -> `A(Post)`
|
|
167
|
-
|
|
168
|
-
### Large Payloads
|
|
169
|
-
|
|
170
|
-
If a payload exceeds SQS size limits, async-lambda automatically stores it in S3 and passes a reference key to the Lambda function.
|
|
171
|
-
|
|
172
|
-
### Dead Letter Queues (DLQ)
|
|
173
|
-
|
|
174
|
-
All async tasks share a DLQ for failed messages. You can configure custom DLQ tasks for advanced error handling.
|
|
175
|
-
|
|
176
|
-
## async-lambda config
|
|
177
|
-
|
|
178
|
-
Configuration options can be set with the `.async_lambda/config.json` file.
|
|
179
|
-
The configuration options can be set at the app, stage, and task level. A configuration option set
|
|
180
|
-
will apply unless overridden at a more specific level (app -> stage -> task -> stage).
|
|
181
|
-
The override logic attempts to be non-destructive so if you have a `layers` of `['layer_1']` at the app level,
|
|
182
|
-
and `[layer_2]` at the stage level, then the value will be `['layer_1', 'layer_2']`.
|
|
183
|
-
|
|
184
|
-
**Config file levels schema**
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
{
|
|
188
|
-
# APP LEVEL
|
|
189
|
-
"stages": {
|
|
190
|
-
"stage_name": {
|
|
191
|
-
# STAGE LEVEL
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
"tasks": {
|
|
195
|
-
"task_id": {
|
|
196
|
-
# TASK LEVEL
|
|
197
|
-
"stages": {
|
|
198
|
-
"stage_name": {
|
|
199
|
-
# TASK STAGE LEVEL
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**At any of these `levels` any of the configuration options can be set:**
|
|
208
|
-
With the exception of `domain_name`, `tls_version`, and `certificate_arn` which can not be set at the task level.
|
|
209
|
-
|
|
210
|
-
### environment_variables
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
{
|
|
214
|
-
"ENV_VAR_NAME": "ENV_VAR_VALUE"
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
This config value will set environment variables for the function execution.
|
|
219
|
-
These environment variables will also be available during build time.
|
|
220
|
-
|
|
221
|
-
[The value is passed to the `Environment` property on `SAM::Serverless::Function`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-environment)
|
|
222
|
-
|
|
223
|
-
### policies
|
|
224
|
-
|
|
225
|
-
```
|
|
226
|
-
[
|
|
227
|
-
'IAM_POLICY_ARN' | STATEMENT
|
|
228
|
-
]
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Use this config option to attach any arbitrary policies to the lambda functions execution role.
|
|
232
|
-
|
|
233
|
-
[The value is passed to the `Policies` property on `SAM::Serverless::Function`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-policies), in addition to the `async-lambda` created inline policies.
|
|
234
|
-
|
|
235
|
-
### layers
|
|
236
|
-
|
|
237
|
-
```
|
|
238
|
-
[
|
|
239
|
-
"LAYER_ARN"
|
|
240
|
-
]
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Use this config option to add any arbitrary lambda layers to the lambda functions. Ordering matters,
|
|
244
|
-
and merging is done thru concatenation.
|
|
245
|
-
|
|
246
|
-
[The value is passed to the `Layers` property on `SAM::Serverless::Function`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-layers)
|
|
247
|
-
|
|
248
|
-
### subnet_ids
|
|
249
|
-
|
|
250
|
-
```
|
|
251
|
-
[
|
|
252
|
-
"SUBNET_ID"
|
|
253
|
-
]
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
Use this config option to put the lambda function into a vpc/subnet.
|
|
257
|
-
|
|
258
|
-
The value is passed into the [`SubnetIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) field of the [`VpcConfig` property on `SAM::Serverless::Function`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-vpcconfig)
|
|
259
|
-
|
|
260
|
-
### security_group_ids
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
[
|
|
264
|
-
"SECURITY_GROUP_ID"
|
|
265
|
-
]
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
Use this config option to attach a security group to the lambda function.
|
|
269
|
-
|
|
270
|
-
The value is passed into the [`SecurityGroupIds`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) field of the [`VpcConfig` property on `SAM::Serverless::Function`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-vpcconfig)
|
|
271
|
-
|
|
272
|
-
### managed_queue_extras
|
|
273
|
-
|
|
274
|
-
```
|
|
275
|
-
[
|
|
276
|
-
{
|
|
277
|
-
# Cloudformation resource
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Use this config option to add extra resources for managed SQS queues (`async_task` tasks.)
|
|
283
|
-
|
|
284
|
-
For example this might be used to attach alarms to these queues.
|
|
285
|
-
|
|
286
|
-
Each item in the list should be a complete cloudformation resource. `async-lambda` provides a few custom substitutions
|
|
287
|
-
so that you can reference the extras and the associated managed sqs resource by `LogicalId`.
|
|
288
|
-
|
|
289
|
-
- `$QUEUEID` will be replaced with the `LogicalId` of the associated Managed SQS queue.
|
|
290
|
-
- `$EXTRA<index>` will be replaced with the `LogicalId` of the extra at the specified index.
|
|
291
|
-
|
|
292
|
-
### method_settings
|
|
293
|
-
|
|
294
|
-
**This config value can only be set at the app or stage level.**
|
|
295
|
-
|
|
296
|
-
```
|
|
297
|
-
[
|
|
298
|
-
{...}
|
|
299
|
-
]
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
|
|
303
|
-
|
|
304
|
-
The value is passed into the [`MethodSettings`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-methodsettings) property of the `AWS::Serverless::Api`. The spec for `MethodSetting` can be found [here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-stage-methodsetting.html).
|
|
305
|
-
|
|
306
|
-
### domain_name
|
|
307
|
-
|
|
308
|
-
**This config value can only be set at the app or stage level.**
|
|
309
|
-
|
|
310
|
-
```
|
|
311
|
-
"domain_name"
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
|
|
315
|
-
|
|
316
|
-
This config value will set the [`DomainName`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) field of the [`Domain` property](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-domain)
|
|
317
|
-
|
|
318
|
-
### tls_version
|
|
319
|
-
|
|
320
|
-
**This config value can only be set at the app or stage level.**
|
|
321
|
-
|
|
322
|
-
```
|
|
323
|
-
"tls_version"
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
|
|
327
|
-
|
|
328
|
-
This config value will set the [`SecurityPolicy`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) field of the [`Domain` property](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-domain)
|
|
329
|
-
|
|
330
|
-
Possible values are `TLS_1_0` and `TLS_1_2`
|
|
331
|
-
|
|
332
|
-
### certificate_arn
|
|
333
|
-
|
|
334
|
-
**This config value can only be set at the app or stage level.**
|
|
335
|
-
|
|
336
|
-
```
|
|
337
|
-
"certificate_arn"
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
|
|
341
|
-
|
|
342
|
-
This config value will set the [`CertificateArn`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) field of the [`Domain` property](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-domain)
|
|
343
|
-
|
|
344
|
-
### hosted_zone_id
|
|
345
|
-
|
|
346
|
-
**This config value can only be set at the app or stage level.**
|
|
347
|
-
|
|
348
|
-
```
|
|
349
|
-
"hosted_zone_id"
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
|
|
353
|
-
|
|
354
|
-
This config value will set the [`HostedZoneId`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) field of the [`Route53`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html#sam-api-domainconfiguration-route53) property of the [`Domain` property](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-domain).
|
|
355
|
-
|
|
356
|
-
This will create a DNS record on the given hosted zone for the api gateway endpoint created by the SAM deployment.
|
|
357
|
-
|
|
358
|
-
### tags
|
|
359
|
-
|
|
360
|
-
```
|
|
361
|
-
{
|
|
362
|
-
"TAG_NAME": "TAG_VALUE"
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
This config value will set the `Tags` field of all resources created by async-lambda. This will not set the field on `managed_queue_extras` resources.
|
|
367
|
-
|
|
368
|
-
The keys `framework` and `framework-version` will always be set and the system values will override any values set by the user.
|
|
369
|
-
|
|
370
|
-
For managed queues the tags `async-lambda-queue-type` will be set to `dlq`, `dlq-task`, or `managed` depending on the queue type.
|
|
371
|
-
|
|
372
|
-
For `async_task` queues (non dlq-task) the `async-lambda-lane` will be set.
|
|
373
|
-
|
|
374
|
-
### logging_config
|
|
375
|
-
|
|
376
|
-
```
|
|
377
|
-
{
|
|
378
|
-
"ApplicationLogLevel": "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL",
|
|
379
|
-
"LogFormat": "Text" | "JSON",
|
|
380
|
-
"LogGroup": "",
|
|
381
|
-
"SystemLogLevel": "DEBUG" | "INFO" | "WARN"
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
The value is passed directly to the [`LoggingConfig`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-loggingconfig) Cloudformation parameter for lambda function/s.
|
|
386
|
-
|
|
387
|
-
See above for full details on configuration schema and merging behavior.
|
|
388
|
-
|
|
389
|
-
## Advanced Usage
|
|
390
|
-
|
|
391
|
-
### Task Initialization
|
|
392
|
-
|
|
393
|
-
Use the `init_tasks` argument to run setup logic during Lambda INIT phase. This is useful for caching, resource allocation, or one-time setup.
|
|
394
|
-
|
|
395
|
-
```python
|
|
396
|
-
def setup_cache(task_id):
|
|
397
|
-
...
|
|
398
|
-
|
|
399
|
-
@app.async_task("TaskID", init_tasks=[setup_cache])
|
|
400
|
-
def async_task(event: ManagedSQSEvent):
|
|
401
|
-
...
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Defer Utility
|
|
405
|
-
|
|
406
|
-
The `Defer` class allows you to cache values during INIT and only execute a function when its value is requested.
|
|
407
|
-
|
|
408
|
-
```python
|
|
409
|
-
cache = Defer(get_a_value, 10, 100)
|
|
410
|
-
|
|
411
|
-
@app.async_task("Task", init_tasks=[cache.execute])
|
|
412
|
-
def task(event: ManagedSQSEvent):
|
|
413
|
-
for i in range(cache.value):
|
|
414
|
-
...
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
## Known Limitations
|
|
418
|
-
|
|
419
|
-
- Not all Lambda configuration options are supported (see code for extension points)
|
|
420
|
-
- Payloads must be JSON serializable
|
|
421
|
-
- Infinite loops are possible if tasks invoke each other recursively
|
|
422
|
-
|
|
423
|
-
## Project Structure
|
|
424
|
-
|
|
425
|
-
- `async_lambda/`: Core framework code
|
|
426
|
-
- `controller.py`: Main controller and orchestration logic
|
|
427
|
-
- `models/`: Event, response, and task models
|
|
428
|
-
- `middleware.py`: Middleware registration and execution
|
|
429
|
-
- `client.py`, `env.py`, `config.py`: AWS clients and configuration
|
|
430
|
-
- `defer.py`: Defer utility for caching
|
|
431
|
-
- `payload_encoder.py`, `util.py`: Utilities
|
|
432
|
-
- `example/`: Example usage and sample app
|
|
433
|
-
- `scripts/`: Linting and testing scripts
|
|
434
|
-
- `test/`: Unit tests
|
|
435
|
-
|
|
436
|
-
## License
|
|
437
|
-
|
|
438
|
-
See LICENSE file for details.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
pyproject.toml
|
|
3
|
-
async_lambda/__init__.py
|
|
4
|
-
async_lambda/build_config.py
|
|
5
|
-
async_lambda/cli.py
|
|
6
|
-
async_lambda/client.py
|
|
7
|
-
async_lambda/config.py
|
|
8
|
-
async_lambda/controller.py
|
|
9
|
-
async_lambda/defer.py
|
|
10
|
-
async_lambda/env.py
|
|
11
|
-
async_lambda/middleware.py
|
|
12
|
-
async_lambda/payload_encoder.py
|
|
13
|
-
async_lambda/py.typed
|
|
14
|
-
async_lambda/util.py
|
|
15
|
-
async_lambda/models/__init__.py
|
|
16
|
-
async_lambda/models/api_response.py
|
|
17
|
-
async_lambda/models/case_insensitive_dict.py
|
|
18
|
-
async_lambda/models/task.py
|
|
19
|
-
async_lambda/models/events/__init__.py
|
|
20
|
-
async_lambda/models/events/api_event.py
|
|
21
|
-
async_lambda/models/events/base_event.py
|
|
22
|
-
async_lambda/models/events/dynamodb_event.py
|
|
23
|
-
async_lambda/models/events/managed_sqs_batch_event.py
|
|
24
|
-
async_lambda/models/events/managed_sqs_event.py
|
|
25
|
-
async_lambda/models/events/scheduled_event.py
|
|
26
|
-
async_lambda/models/events/unmanaged_sqs_event.py
|
|
27
|
-
async_lambda/models/mock/mock_context.py
|
|
28
|
-
async_lambda/models/mock/mock_event.py
|
|
29
|
-
async_lambda_unstable.egg-info/PKG-INFO
|
|
30
|
-
async_lambda_unstable.egg-info/SOURCES.txt
|
|
31
|
-
async_lambda_unstable.egg-info/dependency_links.txt
|
|
32
|
-
async_lambda_unstable.egg-info/entry_points.txt
|
|
33
|
-
async_lambda_unstable.egg-info/requires.txt
|
|
34
|
-
async_lambda_unstable.egg-info/top_level.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
async_lambda
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/api_response.py
RENAMED
|
File without changes
|
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/__init__.py
RENAMED
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/api_event.py
RENAMED
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/events/base_event.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/mock/mock_context.py
RENAMED
|
File without changes
|
{async-lambda-unstable-0.5.7 → async_lambda_unstable-0.6.0}/async_lambda/models/mock/mock_event.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|