django-lambda-tasks 0.6.0__tar.gz → 0.6.2__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.
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/steering/product.md +13 -14
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/steering/structure.md +6 -6
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/PKG-INFO +79 -92
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/README.md +78 -91
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_project/settings.py +3 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/admin.py +0 -8
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/decorators.py +23 -124
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/handler.py +25 -8
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/models.py +28 -19
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/settings.py +52 -33
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/tasks.py +12 -8
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/pyproject.toml +1 -1
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/settings.py +4 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_admin.py +0 -4
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_batch.py +35 -29
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_batch_worker.py +5 -3
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_decorator.py +46 -70
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_local_executor.py +1 -1
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_memory_limit.py +67 -3
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_models.py +23 -19
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_settings.py +74 -48
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_timeout_validation.py +68 -9
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_timeouts.py +1 -0
- django_lambda_tasks-0.6.0/tests/test_batch_decorators.py +0 -158
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.github/workflows/ci.yml +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.github/workflows/release.yml +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.gitignore +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/async-local-execution/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/async-local-execution/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/async-local-execution/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/async-local-execution/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/deferred-task-enqueue/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/deferred-task-enqueue/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/deferred-task-enqueue/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/deferred-task-enqueue/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/eager-mode-example-app/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/eager-mode-example-app/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/eager-mode-example-app/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/eager-mode-example-app/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ignore-errors-decorator-option/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ignore-errors-decorator-option/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ignore-errors-decorator-option/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ignore-errors-decorator-option/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/import-string-task-resolution/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/import-string-task-resolution/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/import-string-task-resolution/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/import-string-task-resolution/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/retry-delay/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/retry-delay/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/retry-delay/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/retry-delay/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks-bugfix/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks-bugfix/bugfix.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks-bugfix/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/rse-background-tasks-bugfix/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/singleton-task/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/singleton-task/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/singleton-task/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/singleton-task/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ssm-environment-loader/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ssm-environment-loader/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ssm-environment-loader/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/ssm-environment-loader/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/task-retry/.config.kiro +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/task-retry/design.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/task-retry/requirements.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/specs/task-retry/tasks.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.kiro/steering/tech.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.pre-commit-config.yaml +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/.vscode/settings.json +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/README.md +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_app/__init__.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_app/apps.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_app/tasks.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_app/urls.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_app/views.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_project/__init__.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_project/urls.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/example_project/wsgi.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/example/manage.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/__init__.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/apps.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/environment_loader.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/local_executor.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/logging.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/migrations/0001_initial.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/migrations/0002_alter_taskrecord_status.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/migrations/__init__.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/secret_loader.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/lambda_tasks/timeouts.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/conftest.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_decorators.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_deferred_enqueue.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_environment_loader.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_handler.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_kwargs_only.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_logging.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_secret_loader.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_serializer.py +0 -0
- {django_lambda_tasks-0.6.0 → django_lambda_tasks-0.6.2}/tests/test_tasks.py +0 -0
|
@@ -14,10 +14,10 @@ A Django library for offloading tasks to AWS Lambda or AWS Batch outside of the
|
|
|
14
14
|
View → @lambda_task.execute_on_commit() → SQS → Lambda handler → SQSLambdaTaskMessage.execute_immediately() → TaskRecord
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
### Batch tasks
|
|
17
|
+
### Batch tasks (via queue config)
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
View → @
|
|
20
|
+
View → @lambda_task(queue="heavy").execute_on_commit() → SQS → Lambda handler → submit_batch_job → batch.submit_job()
|
|
21
21
|
→ Container → python -m lambda_tasks.handler → handler() → execute_immediately() → TaskRecord
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -27,25 +27,25 @@ Container (retry_on exception) → execute_on_commit() → SQS → Lambda → su
|
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
Key modules:
|
|
30
|
-
- `decorators.py` — `
|
|
30
|
+
- `decorators.py` — `LambdaTaskWrapper` and `@lambda_task` decorator factory
|
|
31
31
|
- `models.py` — `TaskRecord` (Django ORM), `SQSLambdaTaskMessage` (SQS schema + execution), `SQSLambdaTask` (routing + SQS publish, Batch submit, or local pool submit)
|
|
32
32
|
- `local_executor.py` — `ProcessPoolExecutor`-based async local execution for development
|
|
33
33
|
- `handler.py` — AWS Lambda entry point + AWS Batch container entry point (`main()`)
|
|
34
34
|
- `logging.py` — `task_logger` for invocation-scoped log output
|
|
35
|
-
- `settings.py` —
|
|
35
|
+
- `settings.py` — lazy `LambdaTasksSettings` reading from Django settings, queue type helpers
|
|
36
36
|
|
|
37
37
|
## Task Definition
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
|
-
# Lambda task — max timeout 900s
|
|
40
|
+
# Lambda task — max timeout determined by queue type (900s for SQS, 3600s for Batch)
|
|
41
41
|
@lambda_task(retry_delay=30, soft_timeout=60, hard_timeout=120, queue="default",
|
|
42
42
|
retry_on=(TransientError,),
|
|
43
43
|
singleton=True, retry_singleton=True)
|
|
44
44
|
def my_task(*, user_id: int, action: str) -> None:
|
|
45
45
|
...
|
|
46
46
|
|
|
47
|
-
# Batch task —
|
|
48
|
-
@
|
|
47
|
+
# Batch task — same decorator, just routed to a Batch queue
|
|
48
|
+
@lambda_task(queue="heavy", soft_timeout=1800, hard_timeout=3500,
|
|
49
49
|
retry_on=(TransientError,))
|
|
50
50
|
def heavy_task(*, file_id: int) -> None:
|
|
51
51
|
...
|
|
@@ -55,7 +55,7 @@ def heavy_task(*, file_id: int) -> None:
|
|
|
55
55
|
- Task files should be named `tasks.py` within the Django app
|
|
56
56
|
- Direct call `my_task(user_id=1, action="x")` runs synchronously
|
|
57
57
|
- `my_task.execute_on_commit(user_id=1, action="x")` enqueues after transaction commit
|
|
58
|
-
-
|
|
58
|
+
- The execution backend (Lambda vs Batch) is determined by the queue configuration, not the decorator
|
|
59
59
|
|
|
60
60
|
## Enqueuing
|
|
61
61
|
|
|
@@ -130,7 +130,7 @@ class SQSLambdaTaskMessage(BaseModel):
|
|
|
130
130
|
`SQSLambdaTaskMessage.execute_immediately(*, message_id: str)` in `models.py`:
|
|
131
131
|
1. Checks for an existing `TaskRecord` with the same `pk` (`message_id`) via `get_or_create`
|
|
132
132
|
2. If a record already exists (any status), logs and returns immediately — duplicate deliveries are silently skipped
|
|
133
|
-
3. Resolves timeouts: decorator default → settings defaults (soft=270s, hard=300s)
|
|
133
|
+
3. Resolves timeouts: decorator default → settings defaults (soft=270s, hard=300s), validated against queue max (900 for SQS, 3600 for Batch)
|
|
134
134
|
4. If `wrapper.singleton` is `True`, acquires a Redis lock via `caches[SINGLETON_CACHE].lock(lock_key)` wrapping the atomic block; if `False`, no lock is acquired
|
|
135
135
|
5. Runs task inside `transaction.atomic()` + `TimeoutContext`
|
|
136
136
|
6. On success: updates record to `SUCCESS` with result and `end_time`
|
|
@@ -196,7 +196,7 @@ Behaviour:
|
|
|
196
196
|
|
|
197
197
|
- `TaskRecord` — Django ORM model; persists task execution state with statuses `RUNNING`, `SUCCESS`, `FAILED`, `RETRYING`
|
|
198
198
|
- `SQSLambdaTaskMessage` — Pydantic model; the SQS message schema; `execute_immediately()` runs the task inside `transaction.atomic()` + `TimeoutContext`
|
|
199
|
-
- `SQSLambdaTask` — Pydantic model; holds a `SQSLambdaTaskMessage` plus routing fields (`delay`, `queue`); `_execute()`
|
|
199
|
+
- `SQSLambdaTask` — Pydantic model; holds a `SQSLambdaTaskMessage` plus routing fields (`delay`, `queue`); `_execute()` inspects queue config to publish to SQS, submit to Batch via `submit_batch_job`, or execute eagerly/locally; `execute_on_commit()` registers `_execute` with `transaction.on_commit`
|
|
200
200
|
|
|
201
201
|
## TaskRecord Model
|
|
202
202
|
|
|
@@ -210,8 +210,7 @@ Statuses: `RUNNING`, `SUCCESS`, `FAILED`, `RETRYING`
|
|
|
210
210
|
|
|
211
211
|
| Setting | Default | Description |
|
|
212
212
|
|---|---|---|
|
|
213
|
-
| `LAMBDA_TASKS_QUEUES` | — | Dict of `{queue_name:
|
|
214
|
-
| `LAMBDA_TASKS_BATCH_QUEUES` | `{}` | Dict of `{queue_name: {"job_queue": ..., "job_definition": ...}}`, must include `"default"` when set |
|
|
213
|
+
| `LAMBDA_TASKS_QUEUES` | — | Dict of `{queue_name: queue_config}`. Each value is a dict with either `queue_url` (SQS) or `job_queue_arn`+`job_definition_arn` (Batch). Must include `"default"` which must be SQS. |
|
|
215
214
|
| `LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT` | `270` | Soft timeout in seconds |
|
|
216
215
|
| `LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT` | `300` | Hard timeout in seconds |
|
|
217
216
|
| `LAMBDA_TASKS_EAGER` | `False` | Run tasks synchronously in-process (no SQS) |
|
|
@@ -219,7 +218,7 @@ Statuses: `RUNNING`, `SUCCESS`, `FAILED`, `RETRYING`
|
|
|
219
218
|
| `LAMBDA_TASKS_MAX_RETRIES` | `2880` | Maximum retry attempts before `MaxRetriesExceededError` is raised (60 × 24 × 2) |
|
|
220
219
|
| `LAMBDA_TASKS_SINGLETON_CACHE` | `"default"` | Django cache backend used for singleton task locks |
|
|
221
220
|
|
|
222
|
-
`LAMBDA_TASKS_QUEUES` must be set and include a `"default"` key. Both timeout values must be greater than zero and
|
|
221
|
+
`LAMBDA_TASKS_QUEUES` must be set and include a `"default"` key. The `"default"` queue must be an SQS queue. Both timeout values must be greater than zero and `soft_timeout` must always be strictly less than `hard_timeout`. The maximum allowed timeout depends on the queue type: 900 for SQS, 3600 for Batch.
|
|
223
222
|
|
|
224
223
|
## Eager Mode
|
|
225
224
|
|
|
@@ -289,7 +288,7 @@ def my_task(*, user_id: int) -> None:
|
|
|
289
288
|
`lambda_tasks.tasks` provides maintenance tasks that ship with the library:
|
|
290
289
|
|
|
291
290
|
- `cleanup_task_records(*, retention_days: int = 7) -> int` — deletes `TaskRecord` rows whose `start_time` is strictly older than `retention_days`. Returns the number of deleted rows. Decorated with `@lambda_task` so it can be enqueued via `cleanup_task_records.execute_on_commit()` or called directly. Users are responsible for scheduling (e.g. EventBridge rule, cron, management command).
|
|
292
|
-
- `submit_batch_job(*, message_json: str, batch_queue: str) -> str` — submits a batch task to AWS Batch. Reads `
|
|
291
|
+
- `submit_batch_job(*, message_json: str, batch_queue: str) -> str` — submits a batch task to AWS Batch. Reads `job_queue_arn` and `job_definition_arn` from `LAMBDA_TASKS_QUEUES[batch_queue]`, sanitizes the task name for use as `jobName`, and calls `batch.submit_job()` with the message passed as a `LAMBDA_TASKS_MESSAGE` environment variable override. Returns the Batch job ID. This task is enqueued automatically by `SQSLambdaTask._execute()` when the queue is a Batch queue — users do not call it directly.
|
|
293
292
|
|
|
294
293
|
## Conventions
|
|
295
294
|
|
|
@@ -12,11 +12,11 @@ django-lambda-tasks/
|
|
|
12
12
|
│ ├── __init__.py
|
|
13
13
|
│ ├── admin.py # Django admin for TaskRecord
|
|
14
14
|
│ ├── apps.py # Django AppConfig
|
|
15
|
-
│ ├── decorators.py #
|
|
15
|
+
│ ├── decorators.py # LambdaTaskWrapper, @lambda_task
|
|
16
16
|
│ ├── handler.py # AWS Lambda entry point + AWS Batch container entry point (main)
|
|
17
17
|
│ ├── logging.py # task_logger — invocation-scoped LoggerAdapter
|
|
18
18
|
│ ├── models.py # TaskRecord, SQSLambdaTaskMessage, SQSLambdaTask
|
|
19
|
-
│ ├── settings.py # LambdaTasksSettings,
|
|
19
|
+
│ ├── settings.py # LambdaTasksSettings, constants, queue type helpers
|
|
20
20
|
│ ├── secret_loader.py # Resolves LAMBDA_TASKS_SECRET_* env vars at cold start
|
|
21
21
|
│ ├── environment_loader.py # Loads env vars from Secrets Manager at cold start
|
|
22
22
|
│ ├── local_executor.py # ProcessPoolExecutor for async local task execution
|
|
@@ -27,7 +27,7 @@ django-lambda-tasks/
|
|
|
27
27
|
│ ├── conftest.py
|
|
28
28
|
│ ├── settings.py # Django settings for test environment
|
|
29
29
|
│ └── test_*.py # One test file per module
|
|
30
|
-
├── example/ # Runnable Django project (
|
|
30
|
+
├── example/ # Runnable Django project (LOCAL_WORKERS mode, no AWS needed)
|
|
31
31
|
│ ├── example_app/ # Sample app with a task definition and trigger view
|
|
32
32
|
│ ├── example_project/ # Django settings, URLs, WSGI
|
|
33
33
|
│ ├── manage.py
|
|
@@ -39,14 +39,14 @@ django-lambda-tasks/
|
|
|
39
39
|
|
|
40
40
|
## Module Responsibilities
|
|
41
41
|
|
|
42
|
-
- `decorators.py` — defines `
|
|
43
|
-
- `models.py` — `TaskRecord` (Django ORM), `SQSLambdaTaskMessage` (Pydantic, SQS schema + execution logic), `SQSLambdaTask` (Pydantic, holds message + routing
|
|
42
|
+
- `decorators.py` — defines `LambdaTaskWrapper` and `@lambda_task` decorator factory; enforces kwargs-only at decoration time; validates timeouts (> 0, soft < hard) at decoration time; upper-bound timeout validation deferred to execution time based on queue type
|
|
43
|
+
- `models.py` — `TaskRecord` (Django ORM), `SQSLambdaTaskMessage` (Pydantic, SQS schema + execution logic), `SQSLambdaTask` (Pydantic, holds message + routing; `_execute()` inspects queue config to publish to SQS, submit to Batch via `submit_batch_job`, execute eagerly, or submit to the local process pool; `execute_on_commit()` registers `_execute` with `transaction.on_commit`)
|
|
44
44
|
- `local_executor.py` — `ProcessPoolExecutor`-based async local execution; `get_pool()` lazily creates a module-level pool; `submit_task()` fire-and-forget submission; `_execute_in_worker()` deserializes and runs the task in a child process; `_pool_initializer()` calls `django.setup()` per worker (and sets `SIGINT` to `SIG_IGN` so workers ignore Ctrl+C); `_install_shutdown_handlers()` installs main-thread `SIGINT`/`SIGTERM` handlers that release the pool before chaining to the previous handler
|
|
45
45
|
- `handler.py` — Lambda entry point (`handler(event, context)`); cold-start init (memory limit → temporary log handler → `resolve_environment()` → `resolve_secrets_into_env()` → handler removed → conditional `django.setup()`) runs inside the handler on first invocation, guarded by `_cold_start_done` sentinel; processes SQS records independently; returns `batchItemFailures`. Also provides `main()` as the AWS Batch container entry point (`python -m lambda_tasks.handler`) — reads `LAMBDA_TASKS_MESSAGE` env var, constructs a synthetic SQS event, and delegates to `handler()`
|
|
46
46
|
- `environment_loader.py` — loads env vars from a Secrets Manager secret at cold start; validates flat JSON format; idempotent via `_loaded` sentinel
|
|
47
47
|
- `secret_loader.py` — resolves `LAMBDA_TASKS_SECRET_*` env vars from Secrets Manager before Django starts; validates format, detects conflicts, batches API calls; idempotent via `_loaded` sentinel
|
|
48
48
|
- `logging.py` — `task_logger` singleton; `message_id` set/cleared around each task execution
|
|
49
|
-
- `settings.py` —
|
|
49
|
+
- `settings.py` — constants (`MAX_DELAY`, `MAX_TIMEOUT`, `MAX_BATCH_TIMEOUT`); `_is_sqs_queue()` and `_is_batch_queue()` helpers; `LambdaTasksSettings` instantiated fresh per use (reads live Django settings); `queue_max_timeout()` method returns 900 or 3600 based on queue type
|
|
50
50
|
- `admin.py` — Django admin registration for `TaskRecord`
|
|
51
51
|
- `apps.py` — Django `AppConfig`; `ready()` installs the local-executor shutdown signal handlers when `LOCAL_WORKERS > 0`
|
|
52
52
|
- `tasks.py` — built-in tasks; `cleanup_task_records` deletes old `TaskRecord` rows; `submit_batch_job` receives a serialized task message and submits it to AWS Batch via `batch.submit_job()`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-lambda-tasks
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Run async tasks in a lambda function
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: awslambdaric
|
|
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
|
|
|
12
12
|
|
|
13
13
|
# Django Lambda Tasks
|
|
14
14
|
|
|
15
|
-
A Django library for offloading work to AWS Lambda outside of the request-response cycle. Tasks are defined with a decorator, enqueued to SQS on transaction commit, and executed by a Lambda handler
|
|
15
|
+
A Django library for offloading work to AWS Lambda or AWS Batch outside of the request-response cycle. Tasks are defined with a decorator, enqueued to SQS on transaction commit, and executed by a Lambda handler or Batch container. Task results, status, and metadata are persisted in the Django database.
|
|
16
16
|
|
|
17
17
|
> **Platform note:** Unix-based systems only (Linux, macOS). Timeout enforcement relies on `SIGALRM`.
|
|
18
18
|
|
|
@@ -86,7 +86,7 @@ See [AWS Lambda and SQS setup](#aws-lambda-and-sqs-setup) for queue and Lambda c
|
|
|
86
86
|
|
|
87
87
|
## Example app
|
|
88
88
|
|
|
89
|
-
A runnable Django project is included in the [`example/`](example/) directory. It uses `
|
|
89
|
+
A runnable Django project is included in the [`example/`](example/) directory. It uses `LAMBDA_TASKS_LOCAL_WORKERS = 2` so no AWS infrastructure is needed.
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
92
|
cd example
|
|
@@ -109,24 +109,25 @@ All settings are read from your Django settings module and prefixed with `LAMBDA
|
|
|
109
109
|
|
|
110
110
|
| Setting | Type | Description |
|
|
111
111
|
|---|---|---|
|
|
112
|
-
| `LAMBDA_TASKS_QUEUES` | `dict[str,
|
|
113
|
-
|
|
112
|
+
| `LAMBDA_TASKS_QUEUES` | `dict[str, dict]` | Map of queue name → queue configuration. Must include a `"default"` key. The `"default"` queue must be an SQS queue. |
|
|
113
|
+
|
|
114
|
+
Each queue value is a dict. The queue type is determined by the keys present:
|
|
115
|
+
|
|
116
|
+
- **SQS queue:** `{"queue_url": "https://sqs.../queue-name"}` — tasks execute on Lambda (max timeout 900s)
|
|
117
|
+
- **Batch queue:** `{"job_queue_arn": "arn:...", "job_definition_arn": "arn:..."}` — tasks execute on AWS Batch (max timeout 3600s)
|
|
114
118
|
|
|
115
119
|
```python
|
|
116
120
|
LAMBDA_TASKS_QUEUES = {
|
|
117
|
-
"default": "https://sqs.us-east-1.amazonaws.com/123456789/default",
|
|
118
|
-
"high_memory": "https://sqs.us-east-1.amazonaws.com/123456789/high-memory",
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"default": {
|
|
123
|
-
"job_queue": "arn:aws:batch:eu-west-1:123456789:job-queue/my-queue",
|
|
124
|
-
"job_definition": "arn:aws:batch:eu-west-1:123456789:job-definition/my-def:1",
|
|
121
|
+
"default": {"queue_url": "https://sqs.us-east-1.amazonaws.com/123456789/default"},
|
|
122
|
+
"high_memory": {"queue_url": "https://sqs.us-east-1.amazonaws.com/123456789/high-memory"},
|
|
123
|
+
"heavy": {
|
|
124
|
+
"job_queue_arn": "arn:aws:batch:eu-west-1:123456789:job-queue/my-queue",
|
|
125
|
+
"job_definition_arn": "arn:aws:batch:eu-west-1:123456789:job-definition/my-def:1",
|
|
125
126
|
},
|
|
126
127
|
}
|
|
127
128
|
```
|
|
128
129
|
|
|
129
|
-
`LAMBDA_TASKS_QUEUES` must be set and must include a `"default"` key, otherwise `ImproperlyConfigured` is raised on first use.
|
|
130
|
+
`LAMBDA_TASKS_QUEUES` must be set and must include a `"default"` key, otherwise `ImproperlyConfigured` is raised on first use. The `"default"` queue must be an SQS queue.
|
|
130
131
|
|
|
131
132
|
### Timeout settings
|
|
132
133
|
|
|
@@ -135,7 +136,7 @@ LAMBDA_TASKS_BATCH_QUEUES = {
|
|
|
135
136
|
| `LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT` | `int` | `270` | Seconds before `SoftTimeLimitExceeded` is raised inside the task. |
|
|
136
137
|
| `LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT` | `int` | `300` | Seconds before the task is forcibly terminated. |
|
|
137
138
|
|
|
138
|
-
Both values must be
|
|
139
|
+
Both values must be greater than zero and `soft_timeout` must always be strictly less than `hard_timeout`. The maximum allowed value depends on the queue type: 900 seconds for SQS queues (Lambda's 15-minute limit), 3600 seconds for Batch queues (1 hour). Upper bound validation happens at execution time based on the task's queue.
|
|
139
140
|
|
|
140
141
|
```python
|
|
141
142
|
LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT = 240
|
|
@@ -225,9 +226,9 @@ def my_task(*, arg: str) -> None:
|
|
|
225
226
|
|
|
226
227
|
| Parameter | Type | Default | Description |
|
|
227
228
|
|---|---|---|---|
|
|
228
|
-
| `soft_timeout` | `int \| None` | `None` (uses global default) | Per-task soft timeout in seconds (
|
|
229
|
-
| `hard_timeout` | `int \| None` | `None` (uses global default) | Per-task hard timeout in seconds (
|
|
230
|
-
| `queue` | `str` | `"default"` | Named queue to route this task to. |
|
|
229
|
+
| `soft_timeout` | `int \| None` | `None` (uses global default) | Per-task soft timeout in seconds. Max depends on queue type (900 for SQS, 3600 for Batch). |
|
|
230
|
+
| `hard_timeout` | `int \| None` | `None` (uses global default) | Per-task hard timeout in seconds. Max depends on queue type (900 for SQS, 3600 for Batch). |
|
|
231
|
+
| `queue` | `str` | `"default"` | Named queue to route this task to. Determines both execution backend and timeout limits. |
|
|
231
232
|
| `retry_on` | `tuple[type[BaseException], ...]` | `()` | Exception types that trigger an automatic retry (see [Automatic retries](#automatic-retries)). |
|
|
232
233
|
| `retry_delay` | `int` | `0` | Base delay in seconds when enqueuing a retry. Jitter (1–5s) is always added; result capped at 900. Requires `retry_on` to be non-empty. |
|
|
233
234
|
| `singleton` | `bool` | `False` | Prevent concurrent execution via a Redis lock (see [Singleton tasks](#singleton-tasks)). |
|
|
@@ -306,26 +307,46 @@ Timeout resolution order (first non-`None` value wins):
|
|
|
306
307
|
1. Per-task decorator default (`soft_timeout` / `hard_timeout` on `@lambda_task`)
|
|
307
308
|
2. Global settings (`LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT` / `LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT`)
|
|
308
309
|
|
|
310
|
+
The maximum allowed timeout is determined by the queue type at execution time: 900 seconds for SQS queues, 3600 seconds for Batch queues.
|
|
311
|
+
|
|
309
312
|
---
|
|
310
313
|
|
|
311
314
|
## Named queues
|
|
312
315
|
|
|
313
|
-
Route tasks to
|
|
316
|
+
Route tasks to different execution backends by assigning them to named queues:
|
|
314
317
|
|
|
315
318
|
```python
|
|
316
319
|
# settings.py
|
|
317
320
|
LAMBDA_TASKS_QUEUES = {
|
|
318
|
-
"default": "https://sqs.us-east-1.amazonaws.com/123456789/default",
|
|
319
|
-
"high_memory": "https://sqs.us-east-1.amazonaws.com/123456789/high-memory",
|
|
321
|
+
"default": {"queue_url": "https://sqs.us-east-1.amazonaws.com/123456789/default"},
|
|
322
|
+
"high_memory": {"queue_url": "https://sqs.us-east-1.amazonaws.com/123456789/high-memory"},
|
|
323
|
+
"heavy": {
|
|
324
|
+
"job_queue_arn": "arn:aws:batch:eu-west-1:123456789:job-queue/my-queue",
|
|
325
|
+
"job_definition_arn": "arn:aws:batch:eu-west-1:123456789:job-definition/my-def:1",
|
|
326
|
+
},
|
|
320
327
|
}
|
|
321
328
|
```
|
|
322
329
|
|
|
323
330
|
```python
|
|
331
|
+
# Runs on Lambda with more memory
|
|
324
332
|
@lambda_task(queue="high_memory")
|
|
325
|
-
def
|
|
333
|
+
def process_images(*, batch_id: int) -> None:
|
|
334
|
+
...
|
|
335
|
+
|
|
336
|
+
# Runs on AWS Batch (up to 1 hour, large disk)
|
|
337
|
+
@lambda_task(queue="heavy", soft_timeout=1800, hard_timeout=3500)
|
|
338
|
+
def process_large_file(*, file_id: int) -> str:
|
|
326
339
|
...
|
|
327
340
|
```
|
|
328
341
|
|
|
342
|
+
Tasks routed to a Batch queue are automatically submitted to AWS Batch via the built-in `submit_batch_job` task. The flow is:
|
|
343
|
+
|
|
344
|
+
1. `execute_on_commit()` enqueues a message to the default SQS queue
|
|
345
|
+
2. The Lambda handler picks up the message and runs `submit_batch_job`
|
|
346
|
+
3. `submit_batch_job` calls `batch.submit_job()` with the task message as a `LAMBDA_TASKS_MESSAGE` environment variable override
|
|
347
|
+
4. The Batch container runs `python -m lambda_tasks.handler`, which reads the env var, performs cold-start init, and calls `execute_immediately()`
|
|
348
|
+
5. The task runs with full timeout enforcement (`SIGALRM`), retry support, and `TaskRecord` tracking
|
|
349
|
+
|
|
329
350
|
---
|
|
330
351
|
|
|
331
352
|
## Task results
|
|
@@ -461,10 +482,11 @@ Each task runs inside a `django.db.transaction.atomic` block. If the task raises
|
|
|
461
482
|
|---|---|---|
|
|
462
483
|
| Task function has positional parameters | `TypeError` | At decoration time |
|
|
463
484
|
| `soft_timeout >= hard_timeout` | `ValueError` | At decoration time |
|
|
464
|
-
| Timeout value exceeds 900
|
|
485
|
+
| Timeout value exceeds queue max (900 or 3600) | `ValueError` | At execution time (timeout resolution) |
|
|
465
486
|
| Unknown queue name | `ImproperlyConfigured` | At `.execute_on_commit()` |
|
|
466
487
|
| `LAMBDA_TASKS_QUEUES` not set | `ImproperlyConfigured` | On first settings access |
|
|
467
488
|
| `LAMBDA_TASKS_QUEUES` missing `"default"` | `ImproperlyConfigured` | On first settings access |
|
|
489
|
+
| `"default"` queue is not SQS | `ImproperlyConfigured` | On first settings access |
|
|
468
490
|
| SQS `send_message` failure | boto3 exception (propagated) | At `.execute_on_commit()` |
|
|
469
491
|
|
|
470
492
|
---
|
|
@@ -473,7 +495,7 @@ Each task runs inside a `django.db.transaction.atomic` block. If the task raises
|
|
|
473
495
|
|
|
474
496
|
### SQS queue configuration
|
|
475
497
|
|
|
476
|
-
Each queue in `LAMBDA_TASKS_QUEUES` should be a standard SQS queue (not FIFO) with the following recommended settings:
|
|
498
|
+
Each SQS queue in `LAMBDA_TASKS_QUEUES` should be a standard SQS queue (not FIFO) with the following recommended settings:
|
|
477
499
|
|
|
478
500
|
- **Visibility timeout** — set this higher than your Lambda function's `hard_timeout`. If the Lambda times out before SQS receives a deletion confirmation, the message becomes visible again and will be redelivered.
|
|
479
501
|
- **Dead letter queue (DLQ)** — configure a DLQ to capture messages that cannot be processed. Without one, messages that exhaust retries are silently deleted.
|
|
@@ -600,6 +622,39 @@ The following all raise `ValueError` at cold start, preventing the Lambda contai
|
|
|
600
622
|
|
|
601
623
|
---
|
|
602
624
|
|
|
625
|
+
## AWS Batch setup
|
|
626
|
+
|
|
627
|
+
For tasks that exceed Lambda's 15-minute timeout or 10GB ephemeral storage limit, route them to a Batch queue:
|
|
628
|
+
|
|
629
|
+
```python
|
|
630
|
+
@lambda_task(queue="heavy", soft_timeout=1800, hard_timeout=3500)
|
|
631
|
+
def process_large_file(*, file_id: int) -> str:
|
|
632
|
+
# long-running work with large disk usage
|
|
633
|
+
return "done"
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Batch job definition setup
|
|
637
|
+
|
|
638
|
+
Your Batch job definition should:
|
|
639
|
+
- Use the same Docker image as your application
|
|
640
|
+
- Set `DJANGO_SETTINGS_MODULE` as an environment variable
|
|
641
|
+
- Configure secrets via the job definition's `secrets` field or via `LAMBDA_TASKS_ENVIRONMENT_SECRETS_MANAGER_ARN` / `LAMBDA_TASKS_SECRET_*` env vars (same mechanism as Lambda)
|
|
642
|
+
- Set the default command to `["python", "-m", "lambda_tasks.handler"]`
|
|
643
|
+
|
|
644
|
+
### Retries
|
|
645
|
+
|
|
646
|
+
Batch tasks support `retry_on` — when a retryable exception is raised, the retry goes back through SQS → Lambda → `submit_batch_job` → new Batch job. The same `LAMBDA_TASKS_MAX_RETRIES` limit applies.
|
|
647
|
+
|
|
648
|
+
### Container overrides limit
|
|
649
|
+
|
|
650
|
+
The total `containerOverrides` payload (including JSON formatting) is limited to 8192 characters by AWS Batch. For typical task kwargs (IDs, short strings) this is not a concern.
|
|
651
|
+
|
|
652
|
+
### Eager and local worker modes
|
|
653
|
+
|
|
654
|
+
Tasks on Batch queues respect `LAMBDA_TASKS_EAGER` and `LAMBDA_TASKS_LOCAL_WORKERS` — in development, they run in-process or in the local process pool just like SQS-backed tasks, without requiring AWS infrastructure.
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
603
658
|
## Built-in tasks
|
|
604
659
|
|
|
605
660
|
### `cleanup_task_records`
|
|
@@ -631,71 +686,3 @@ result = send_welcome_email(user_id=1, template="welcome")
|
|
|
631
686
|
```
|
|
632
687
|
|
|
633
688
|
This bypasses the queue entirely and runs the function in the current process. No `TaskRecord` is created, no `transaction.atomic()` block is used, and no timeout enforcement applies — it behaves exactly like calling the underlying function directly. Kwargs are still validated against the task's type annotations via Pydantic.
|
|
634
|
-
|
|
635
|
-
---
|
|
636
|
-
|
|
637
|
-
## AWS Batch tasks
|
|
638
|
-
|
|
639
|
-
For tasks that exceed Lambda's 15-minute timeout or 10GB ephemeral storage limit, use `@batch_task` to route execution to AWS Batch containers.
|
|
640
|
-
|
|
641
|
-
### 1. Define a batch task
|
|
642
|
-
|
|
643
|
-
```python
|
|
644
|
-
# myapp/tasks.py
|
|
645
|
-
from lambda_tasks.decorators import batch_task
|
|
646
|
-
|
|
647
|
-
@batch_task(soft_timeout=1800, hard_timeout=3500)
|
|
648
|
-
def process_large_file(*, file_id: int) -> str:
|
|
649
|
-
# long-running work with large disk usage
|
|
650
|
-
return "done"
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
### 2. Configure AWS Batch queues
|
|
654
|
-
|
|
655
|
-
```python
|
|
656
|
-
# settings.py
|
|
657
|
-
LAMBDA_TASKS_BATCH_QUEUES = {
|
|
658
|
-
"default": {
|
|
659
|
-
"job_queue": "arn:aws:batch:eu-west-1:123456789:job-queue/my-queue",
|
|
660
|
-
"job_definition": "arn:aws:batch:eu-west-1:123456789:job-definition/my-def:1",
|
|
661
|
-
},
|
|
662
|
-
}
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
### 3. Enqueue from a view
|
|
666
|
-
|
|
667
|
-
```python
|
|
668
|
-
process_large_file.execute_on_commit(file_id=42)
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
### How it works
|
|
672
|
-
|
|
673
|
-
1. `execute_on_commit()` enqueues a message to SQS (same as Lambda tasks)
|
|
674
|
-
2. The Lambda handler picks up the message and runs the built-in `submit_batch_job` task
|
|
675
|
-
3. `submit_batch_job` calls `batch.submit_job()` with the task message as a `LAMBDA_TASKS_MESSAGE` environment variable override
|
|
676
|
-
4. The Batch container runs `python -m lambda_tasks.handler`, which reads the env var, performs cold-start init, and calls `execute_immediately()`
|
|
677
|
-
5. The task runs with full timeout enforcement (`SIGALRM`), retry support, and `TaskRecord` tracking
|
|
678
|
-
|
|
679
|
-
### Batch task timeouts
|
|
680
|
-
|
|
681
|
-
Batch tasks support the same two-phase timeout mechanism as Lambda tasks (soft + hard), but with a maximum of **3600 seconds** (1 hour) instead of 900.
|
|
682
|
-
|
|
683
|
-
### Retries
|
|
684
|
-
|
|
685
|
-
Batch tasks support `retry_on` — when a retryable exception is raised, the retry goes back through SQS → Lambda → `submit_batch_job` → new Batch job. The same `LAMBDA_TASKS_MAX_RETRIES` limit applies.
|
|
686
|
-
|
|
687
|
-
### Batch job definition setup
|
|
688
|
-
|
|
689
|
-
Your Batch job definition should:
|
|
690
|
-
- Use the same Docker image as your application
|
|
691
|
-
- Set `DJANGO_SETTINGS_MODULE` as an environment variable
|
|
692
|
-
- Configure secrets via the job definition's `secrets` field or via `LAMBDA_TASKS_ENVIRONMENT_SECRETS_MANAGER_ARN` / `LAMBDA_TASKS_SECRET_*` env vars (same mechanism as Lambda)
|
|
693
|
-
- Set the default command to `["python", "-m", "lambda_tasks.handler"]`
|
|
694
|
-
|
|
695
|
-
### Container overrides limit
|
|
696
|
-
|
|
697
|
-
The total `containerOverrides` payload (including JSON formatting) is limited to 8192 characters by AWS Batch. For typical task kwargs (IDs, short strings) this is not a concern.
|
|
698
|
-
|
|
699
|
-
### Eager and local worker modes
|
|
700
|
-
|
|
701
|
-
Batch tasks respect `LAMBDA_TASKS_EAGER` and `LAMBDA_TASKS_LOCAL_WORKERS` — in development, they run in-process or in the local process pool just like Lambda tasks, without requiring AWS infrastructure.
|