async-lambda-unstable 0.5.9__py2.py3-none-any.whl

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/py.typed ADDED
File without changes
@@ -0,0 +1,442 @@
1
+ Metadata-Version: 2.4
2
+ Name: async-lambda-unstable
3
+ Version: 0.5.9
4
+ Summary: A framework for creating AWS Lambda Async Workflows. - Unstable Branch
5
+ Author-email: "Nuclei, Inc" <engineering@nuclei.ai>
6
+ Requires-Dist: click>=8.0.0
7
+ Requires-Dist: typing-extensions>=4.0.0
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
12
+
13
+ # async-lambda
14
+
15
+ 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.
16
+
17
+ `async-lambda` converts your application into a `Serverless Application Model (SAM)`
18
+ template which can be deployed with the `SAM` cli tool or via Cloudformation.
19
+
20
+ ## Features
21
+
22
+ - **Async Task Abstraction**: Define tasks as Lambda functions triggered by SQS, API Gateway, DynamoDB Streams, or scheduled events.
23
+ - **Automatic SAM Template Generation**: Converts your application into a Serverless Application Model (SAM) template for deployment.
24
+ - **Lane-based Parallelism**: Scale async tasks horizontally using multiple SQS queues (lanes) and control concurrency per lane.
25
+ - **Middleware Support**: Register middleware to wrap task execution, enabling cross-cutting concerns (logging, auth, etc.).
26
+ - **Large Payload Handling**: Offload large payloads to S3 automatically when exceeding SQS size limits.
27
+ - **Dead Letter Queues (DLQ)**: Robust error handling and message redrive for failed async invocations.
28
+ - **Configurable via Code and JSON**: Set configuration at the app, stage, and task level using Python or config files.
29
+ - **Task Initialization**: Run custom logic during Lambda INIT phase for caching, setup, or resource allocation.
30
+
31
+ ## Getting Started
32
+
33
+ ### Installation
34
+
35
+ Add async-lambda to your project (see requirements in `pyproject.toml`).
36
+
37
+ ### Basic Usage
38
+
39
+ ```python
40
+ from async_lambda import AsyncLambdaController, config_set_name, ScheduledEvent, ManagedSQSEvent
41
+
42
+ app = AsyncLambdaController()
43
+ config_set_name("project-name")
44
+ lambda_handler = app.async_lambda_handler # Required Lambda export
45
+
46
+ @app.scheduled_task('ScheduledTask1', schedule_expression="rate(15 minutes)")
47
+ def scheduled_task_1(event: ScheduledEvent):
48
+ app.async_invoke("AsyncTask1", payload={"foo": "bar"})
49
+
50
+ @app.async_task('AsyncTask1')
51
+ def async_task_2(event: ManagedSQSEvent):
52
+ print(event.payload) # {"foo": "bar"}
53
+ ```
54
+
55
+ ### Packaging & Deployment
56
+
57
+ Use the async-lambda CLI to build and package your app:
58
+
59
+ ```bash
60
+ async-lambda build app --stage <stage-name>
61
+ ```
62
+
63
+ This generates a SAM template (`template.json`) and deployment bundle (`deployment.zip`). Deploy using AWS SAM CLI or CloudFormation.
64
+
65
+ ## Core Concepts
66
+
67
+ ### Controller & Tasks
68
+
69
+ - **AsyncLambdaController**: Central orchestrator for registering tasks, managing middleware, and handling invocations.
70
+ - **Task**: Each task is a Lambda function with a unique `task_id` and a trigger type (SQS, API, DynamoDB, schedule).
71
+
72
+ #### Task Decorators
73
+
74
+ All task decorators accept common configuration arguments:
75
+ - `memory`: Memory allocation (MB)
76
+ - `timeout`: Timeout (seconds)
77
+ - `ephemeral_storage`: Ephemeral storage (MB)
78
+ - `maximum_concurrency`: Max concurrency for SQS triggers (int or list per lane)
79
+ - `lane_count`: Number of parallel lanes (for async tasks)
80
+ - `init_tasks`: Functions to run during Lambda INIT phase
81
+
82
+ #### Example: Async Task
83
+
84
+ ```python
85
+ @app.async_task("TaskID")
86
+ def async_task(event: ManagedSQSEvent):
87
+ print(event.payload)
88
+ ```
89
+
90
+
91
+ **It is quite easy to get into infinite looping situations when utilizing `async-lambda` and care should be taken.**
92
+
93
+ **INFINITE LOOP EXAMPLE**
94
+
95
+ ```python
96
+ # If task_1 where to ever get invoked, then it would start an infinite loop with
97
+ # task 1 invoking task 2, task 2 invoking task 1, and repeat...
98
+
99
+ @app.async_task("Task1")
100
+ def task_1(event: ManagedSQSEvent):
101
+ app.async_invoke("Task2", {})
102
+
103
+ @app.async_task("Task2")
104
+ def task_1(event: ManagedSQSEvent):
105
+ app.async_invoke("Task1", {})
106
+ ```
107
+
108
+ #### Example: Scheduled Task
109
+
110
+ ```python
111
+ @app.scheduled_task("TaskID", schedule_expression='rate(15 minutes)')
112
+ def scheduled_task(event: ScheduledEvent):
113
+ ...
114
+ ```
115
+
116
+ #### Example: API Task
117
+
118
+ ```python
119
+ @app.api_task("TaskID", path='/test', method='get')
120
+ def api_task(event: APIEvent):
121
+ print(event.headers)
122
+ print(event.querystring_params)
123
+ print(event.body)
124
+ ```
125
+
126
+ #### Example: Unmanaged SQS Task
127
+
128
+ ```python
129
+ @app.sqs_task("TaskID", queue_arn='queue-arn')
130
+ def sqs_task(event: UnmanagedSQSEvent):
131
+ print(event.body)
132
+ ```
133
+
134
+ ### Lanes & Concurrency
135
+
136
+ 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.
137
+
138
+ ```python
139
+ app = AsyncLambdaController(lane_count=2)
140
+
141
+ @app.async_task("SwitchBoard")
142
+ def switch_board(event: ManagedSQSEvent):
143
+ lane = 1 if event.payload['value'] > 50000 else 0
144
+ app.async_invoke("ProcessingTask", event.payload, lane=lane)
145
+
146
+ @app.async_task("ProcessingTask", maximum_concurrency=[10, 2])
147
+ def processing_task(event: ManagedSQSEvent):
148
+ ...
149
+ ```
150
+
151
+ ### Middleware
152
+
153
+ Middleware functions wrap task execution and can be used for logging, authentication, or modifying events/responses.
154
+
155
+ ```python
156
+ def async_lambda_middleware(event, call_next):
157
+ print(f"Invocation Payload: {event}")
158
+ result = call_next(event)
159
+ print(f"Invocation Result: {result}")
160
+ return result
161
+
162
+ controller = AsyncLambdaController(middleware=[([BaseEvent], async_lambda_middleware)])
163
+ ```
164
+
165
+ If there are multiple middleware functions then `call_next` will actually be calling the next middleware function in the stack.
166
+
167
+ For example if there is middleware functions `A` and `B` registered in that order.
168
+ Then the execution order would go:
169
+
170
+ `A(Pre)` -> `B(Pre)` -> `Task` -> `B(Post)` -> `A(Post)`
171
+
172
+ ### Large Payloads
173
+
174
+ If a payload exceeds SQS size limits, async-lambda automatically stores it in S3 and passes a reference key to the Lambda function.
175
+
176
+ ### Dead Letter Queues (DLQ)
177
+
178
+ All async tasks share a DLQ for failed messages. You can configure custom DLQ tasks for advanced error handling.
179
+
180
+ ## async-lambda config
181
+
182
+ Configuration options can be set with the `.async_lambda/config.json` file.
183
+ The configuration options can be set at the app, stage, and task level. A configuration option set
184
+ will apply unless overridden at a more specific level (app -> stage -> task -> stage).
185
+ The override logic attempts to be non-destructive so if you have a `layers` of `['layer_1']` at the app level,
186
+ and `[layer_2]` at the stage level, then the value will be `['layer_1', 'layer_2']`.
187
+
188
+ **Config file levels schema**
189
+
190
+ ```
191
+ {
192
+ # APP LEVEL
193
+ "stages": {
194
+ "stage_name": {
195
+ # STAGE LEVEL
196
+ }
197
+ },
198
+ "tasks": {
199
+ "task_id": {
200
+ # TASK LEVEL
201
+ "stages": {
202
+ "stage_name": {
203
+ # TASK STAGE LEVEL
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ **At any of these `levels` any of the configuration options can be set:**
212
+ With the exception of `domain_name`, `tls_version`, and `certificate_arn` which can not be set at the task level.
213
+
214
+ ### environment_variables
215
+
216
+ ```
217
+ {
218
+ "ENV_VAR_NAME": "ENV_VAR_VALUE"
219
+ }
220
+ ```
221
+
222
+ This config value will set environment variables for the function execution.
223
+ These environment variables will also be available during build time.
224
+
225
+ [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)
226
+
227
+ ### policies
228
+
229
+ ```
230
+ [
231
+ 'IAM_POLICY_ARN' | STATEMENT
232
+ ]
233
+ ```
234
+
235
+ Use this config option to attach any arbitrary policies to the lambda functions execution role.
236
+
237
+ [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.
238
+
239
+ ### layers
240
+
241
+ ```
242
+ [
243
+ "LAYER_ARN"
244
+ ]
245
+ ```
246
+
247
+ Use this config option to add any arbitrary lambda layers to the lambda functions. Ordering matters,
248
+ and merging is done thru concatenation.
249
+
250
+ [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)
251
+
252
+ ### subnet_ids
253
+
254
+ ```
255
+ [
256
+ "SUBNET_ID"
257
+ ]
258
+ ```
259
+
260
+ Use this config option to put the lambda function into a vpc/subnet.
261
+
262
+ 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)
263
+
264
+ ### security_group_ids
265
+
266
+ ```
267
+ [
268
+ "SECURITY_GROUP_ID"
269
+ ]
270
+ ```
271
+
272
+ Use this config option to attach a security group to the lambda function.
273
+
274
+ 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)
275
+
276
+ ### managed_queue_extras
277
+
278
+ ```
279
+ [
280
+ {
281
+ # Cloudformation resource
282
+ }
283
+ ]
284
+ ```
285
+
286
+ Use this config option to add extra resources for managed SQS queues (`async_task` tasks.)
287
+
288
+ For example this might be used to attach alarms to these queues.
289
+
290
+ Each item in the list should be a complete cloudformation resource. `async-lambda` provides a few custom substitutions
291
+ so that you can reference the extras and the associated managed sqs resource by `LogicalId`.
292
+
293
+ - `$QUEUEID` will be replaced with the `LogicalId` of the associated Managed SQS queue.
294
+ - `$EXTRA<index>` will be replaced with the `LogicalId` of the extra at the specified index.
295
+
296
+ ### method_settings
297
+
298
+ **This config value can only be set at the app or stage level.**
299
+
300
+ ```
301
+ [
302
+ {...}
303
+ ]
304
+ ```
305
+
306
+ If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
307
+
308
+ 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).
309
+
310
+ ### domain_name
311
+
312
+ **This config value can only be set at the app or stage level.**
313
+
314
+ ```
315
+ "domain_name"
316
+ ```
317
+
318
+ If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
319
+
320
+ 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)
321
+
322
+ ### tls_version
323
+
324
+ **This config value can only be set at the app or stage level.**
325
+
326
+ ```
327
+ "tls_version"
328
+ ```
329
+
330
+ If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
331
+
332
+ 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)
333
+
334
+ Possible values are `TLS_1_0` and `TLS_1_2`
335
+
336
+ ### certificate_arn
337
+
338
+ **This config value can only be set at the app or stage level.**
339
+
340
+ ```
341
+ "certificate_arn"
342
+ ```
343
+
344
+ If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
345
+
346
+ 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)
347
+
348
+ ### hosted_zone_id
349
+
350
+ **This config value can only be set at the app or stage level.**
351
+
352
+ ```
353
+ "hosted_zone_id"
354
+ ```
355
+
356
+ If your `async-lambda` app contains any `api_task` tasks, then a `AWS::Serverless::Api` resource is created.
357
+
358
+ 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).
359
+
360
+ This will create a DNS record on the given hosted zone for the api gateway endpoint created by the SAM deployment.
361
+
362
+ ### tags
363
+
364
+ ```
365
+ {
366
+ "TAG_NAME": "TAG_VALUE"
367
+ }
368
+ ```
369
+
370
+ 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.
371
+
372
+ The keys `framework` and `framework-version` will always be set and the system values will override any values set by the user.
373
+
374
+ For managed queues the tags `async-lambda-queue-type` will be set to `dlq`, `dlq-task`, or `managed` depending on the queue type.
375
+
376
+ For `async_task` queues (non dlq-task) the `async-lambda-lane` will be set.
377
+
378
+ ### logging_config
379
+
380
+ ```
381
+ {
382
+ "ApplicationLogLevel": "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL",
383
+ "LogFormat": "Text" | "JSON",
384
+ "LogGroup": "",
385
+ "SystemLogLevel": "DEBUG" | "INFO" | "WARN"
386
+ }
387
+ ```
388
+
389
+ 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.
390
+
391
+ See above for full details on configuration schema and merging behavior.
392
+
393
+ ## Advanced Usage
394
+
395
+ ### Task Initialization
396
+
397
+ Use the `init_tasks` argument to run setup logic during Lambda INIT phase. This is useful for caching, resource allocation, or one-time setup.
398
+
399
+ ```python
400
+ def setup_cache(task_id):
401
+ ...
402
+
403
+ @app.async_task("TaskID", init_tasks=[setup_cache])
404
+ def async_task(event: ManagedSQSEvent):
405
+ ...
406
+ ```
407
+
408
+ ### Defer Utility
409
+
410
+ The `Defer` class allows you to cache values during INIT and only execute a function when its value is requested.
411
+
412
+ ```python
413
+ cache = Defer(get_a_value, 10, 100)
414
+
415
+ @app.async_task("Task", init_tasks=[cache.execute])
416
+ def task(event: ManagedSQSEvent):
417
+ for i in range(cache.value):
418
+ ...
419
+ ```
420
+
421
+ ## Known Limitations
422
+
423
+ - Not all Lambda configuration options are supported (see code for extension points)
424
+ - Payloads must be JSON serializable
425
+ - Infinite loops are possible if tasks invoke each other recursively
426
+
427
+ ## Project Structure
428
+
429
+ - `async_lambda/`: Core framework code
430
+ - `controller.py`: Main controller and orchestration logic
431
+ - `models/`: Event, response, and task models
432
+ - `middleware.py`: Middleware registration and execution
433
+ - `client.py`, `env.py`, `config.py`: AWS clients and configuration
434
+ - `defer.py`: Defer utility for caching
435
+ - `payload_encoder.py`, `util.py`: Utilities
436
+ - `example/`: Example usage and sample app
437
+ - `scripts/`: Linting and testing scripts
438
+ - `test/`: Unit tests
439
+
440
+ ## License
441
+
442
+ See LICENSE file for details.
@@ -0,0 +1,5 @@
1
+ async_lambda/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ async_lambda_unstable-0.5.9.dist-info/METADATA,sha256=qJygkfvLkh39O5wMLL9Y33N9lzP8IPHURsrgfbYaA0o,15772
3
+ async_lambda_unstable-0.5.9.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
4
+ async_lambda_unstable-0.5.9.dist-info/entry_points.txt,sha256=AbP4rv5mUiWKzYwAGe-dUiKokUtKR-6HFpqoAAQ0u1E,54
5
+ async_lambda_unstable-0.5.9.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ async-lambda = async_lambda.cli:cli