django-lambda-tasks 0.1.4__tar.gz → 0.1.5__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.1.4 → django_lambda_tasks-0.1.5}/.kiro/steering/product.md +1 -1
- django_lambda_tasks-0.1.4/README.md → django_lambda_tasks-0.1.5/PKG-INFO +12 -20
- django_lambda_tasks-0.1.4/PKG-INFO → django_lambda_tasks-0.1.5/README.md +0 -31
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/decorators.py +17 -3
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/handler.py +1 -2
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/pyproject.toml +2 -1
- django_lambda_tasks-0.1.5/tests/test_timeout_validation.py +170 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.github/workflows/ci.yml +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.github/workflows/release.yml +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.gitignore +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/ignore-errors-decorator-option/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/ignore-errors-decorator-option/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/ignore-errors-decorator-option/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/ignore-errors-decorator-option/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/import-string-task-resolution/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/import-string-task-resolution/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/import-string-task-resolution/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/import-string-task-resolution/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks-bugfix/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks-bugfix/bugfix.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks-bugfix/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks-bugfix/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/task-retry/.config.kiro +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/task-retry/design.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/task-retry/requirements.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/task-retry/tasks.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/steering/structure.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/steering/tech.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.pre-commit-config.yaml +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.vscode/settings.json +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/README.md +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_app/__init__.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_app/apps.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_app/tasks.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_app/urls.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_app/views.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_project/__init__.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_project/settings.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_project/urls.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/example_project/wsgi.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/example/manage.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/__init__.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/admin.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/apps.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/logging.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/migrations/0001_initial.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/migrations/__init__.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/models.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/secret_loader.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/settings.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/tasks.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/timeouts.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/conftest.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/settings.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_admin.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_decorator.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_decorators.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_deferred_enqueue.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_handler.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_kwargs_only.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_logging.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_models.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_secret_loader.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_serializer.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_settings.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_tasks.py +0 -0
- {django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/tests/test_timeouts.py +0 -0
|
@@ -178,7 +178,7 @@ Statuses: `RUNNING`, `SUCCESS`, `FAILED`, `RETRYING`
|
|
|
178
178
|
| `LAMBDA_TASKS_MAX_RETRIES` | `2880` | Maximum retry attempts before `MaxRetriesExceededError` is raised (60 × 24 × 2) |
|
|
179
179
|
| `LAMBDA_TASKS_SINGLETON_CACHE` | `"default"` | Django cache backend used for singleton task locks |
|
|
180
180
|
|
|
181
|
-
`LAMBDA_TASKS_QUEUES` must be set and include a `"default"` key. `soft_timeout` must always be strictly less than `hard_timeout`.
|
|
181
|
+
`LAMBDA_TASKS_QUEUES` must be set and include a `"default"` key. Both timeout values must be greater than zero and at most `900` seconds. `soft_timeout` must always be strictly less than `hard_timeout`.
|
|
182
182
|
|
|
183
183
|
## Eager Mode
|
|
184
184
|
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-lambda-tasks
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: Run async tasks in a lambda function
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: awslambdaric
|
|
7
|
+
Requires-Dist: boto3
|
|
8
|
+
Requires-Dist: django
|
|
9
|
+
Requires-Dist: pydantic
|
|
10
|
+
Requires-Dist: redis
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
1
13
|
# Django Lambda Tasks
|
|
2
14
|
|
|
3
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 that AWS invokes with SQS message batches. Task results, status, and metadata are persisted in the Django database.
|
|
@@ -162,24 +174,6 @@ def my_task(*, arg: str) -> None:
|
|
|
162
174
|
|
|
163
175
|
---
|
|
164
176
|
|
|
165
|
-
## Per-invocation overrides
|
|
166
|
-
|
|
167
|
-
Pass override kwargs prefixed with `_` to `.execute_on_commit()` to customise a single invocation:
|
|
168
|
-
|
|
169
|
-
```python
|
|
170
|
-
send_welcome_email.execute_on_commit(
|
|
171
|
-
user_id=42,
|
|
172
|
-
template="welcome",
|
|
173
|
-
_delay=30, # SQS message visibility delay in seconds
|
|
174
|
-
)
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
| Override | Type | Description |
|
|
178
|
-
|---|---|---|
|
|
179
|
-
| `_delay` | `int` | SQS message delay in seconds before the worker can pick it up. |
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
177
|
## Serializing a task invocation
|
|
184
178
|
|
|
185
179
|
`serialize()` builds and validates a task invocation the same way `execute_on_commit()` does, but returns the payload as a plain dict instead of enqueuing it. Useful when you need to inspect, store, or forward the message before deciding to send it.
|
|
@@ -196,8 +190,6 @@ payload = send_welcome_email.serialize(user_id=42, template="welcome")
|
|
|
196
190
|
# }
|
|
197
191
|
```
|
|
198
192
|
|
|
199
|
-
Per-invocation overrides (`_delay`) are accepted the same way as in `execute_on_commit()`.
|
|
200
|
-
|
|
201
193
|
The returned dict matches the `SQSLambdaTask` schema. To reconstruct and enqueue it later:
|
|
202
194
|
|
|
203
195
|
```python
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: django-lambda-tasks
|
|
3
|
-
Version: 0.1.4
|
|
4
|
-
Summary: Run async tasks in a lambda function
|
|
5
|
-
Requires-Python: >=3.10
|
|
6
|
-
Requires-Dist: boto3
|
|
7
|
-
Requires-Dist: django
|
|
8
|
-
Requires-Dist: pydantic
|
|
9
|
-
Requires-Dist: redis
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
|
|
12
1
|
# Django Lambda Tasks
|
|
13
2
|
|
|
14
3
|
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 that AWS invokes with SQS message batches. Task results, status, and metadata are persisted in the Django database.
|
|
@@ -173,24 +162,6 @@ def my_task(*, arg: str) -> None:
|
|
|
173
162
|
|
|
174
163
|
---
|
|
175
164
|
|
|
176
|
-
## Per-invocation overrides
|
|
177
|
-
|
|
178
|
-
Pass override kwargs prefixed with `_` to `.execute_on_commit()` to customise a single invocation:
|
|
179
|
-
|
|
180
|
-
```python
|
|
181
|
-
send_welcome_email.execute_on_commit(
|
|
182
|
-
user_id=42,
|
|
183
|
-
template="welcome",
|
|
184
|
-
_delay=30, # SQS message visibility delay in seconds
|
|
185
|
-
)
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
| Override | Type | Description |
|
|
189
|
-
|---|---|---|
|
|
190
|
-
| `_delay` | `int` | SQS message delay in seconds before the worker can pick it up. |
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
165
|
## Serializing a task invocation
|
|
195
166
|
|
|
196
167
|
`serialize()` builds and validates a task invocation the same way `execute_on_commit()` does, but returns the payload as a plain dict instead of enqueuing it. Useful when you need to inspect, store, or forward the message before deciding to send it.
|
|
@@ -207,8 +178,6 @@ payload = send_welcome_email.serialize(user_id=42, template="welcome")
|
|
|
207
178
|
# }
|
|
208
179
|
```
|
|
209
180
|
|
|
210
|
-
Per-invocation overrides (`_delay`) are accepted the same way as in `execute_on_commit()`.
|
|
211
|
-
|
|
212
181
|
The returned dict matches the `SQSLambdaTask` schema. To reconstruct and enqueue it later:
|
|
213
182
|
|
|
214
183
|
```python
|
|
@@ -101,7 +101,9 @@ class LambdaTaskWrapper:
|
|
|
101
101
|
"""Return (soft_timeout, hard_timeout) resolved against settings defaults.
|
|
102
102
|
|
|
103
103
|
Merges decorator-supplied values with settings defaults, then validates
|
|
104
|
-
the final pair.
|
|
104
|
+
the final pair. Each resolved value must be greater than zero and at
|
|
105
|
+
most ``MAX_TIMEOUT`` (900), and ``soft_timeout`` must be strictly less
|
|
106
|
+
than ``hard_timeout``. Result is cached after first access.
|
|
105
107
|
"""
|
|
106
108
|
try:
|
|
107
109
|
return self._resolved_timeouts_cache
|
|
@@ -120,11 +122,15 @@ class LambdaTaskWrapper:
|
|
|
120
122
|
else conf.DEFAULT_HARD_TIMEOUT
|
|
121
123
|
)
|
|
122
124
|
|
|
123
|
-
# Validate settings-sourced values
|
|
125
|
+
# Validate settings-sourced values (decorator values are already checked at decoration time)
|
|
124
126
|
for name, value, source in (
|
|
125
127
|
("soft_timeout", soft, self._soft_timeout),
|
|
126
128
|
("hard_timeout", hard, self._hard_timeout),
|
|
127
129
|
):
|
|
130
|
+
if source is None and value <= 0:
|
|
131
|
+
raise ValueError(
|
|
132
|
+
f"{name} ({value}) from settings must be greater than zero."
|
|
133
|
+
)
|
|
128
134
|
if source is None and value > MAX_TIMEOUT:
|
|
129
135
|
raise ValueError(
|
|
130
136
|
f"{name} ({value}) from settings exceeds the maximum allowed value of {MAX_TIMEOUT} seconds."
|
|
@@ -313,15 +319,23 @@ class LambdaTaskWrapper:
|
|
|
313
319
|
def _validate_timeouts(
|
|
314
320
|
*, soft_timeout: int | None, hard_timeout: int | None
|
|
315
321
|
) -> None:
|
|
316
|
-
"""Raise ValueError if any timeout
|
|
322
|
+
"""Raise ValueError if any timeout is not in (0, 900] or soft_timeout >= hard_timeout.
|
|
323
|
+
|
|
324
|
+
Each timeout, when supplied, must be greater than zero and at most
|
|
325
|
+
``MAX_TIMEOUT`` (900). When both are supplied, ``soft_timeout`` must
|
|
326
|
+
be strictly less than ``hard_timeout``.
|
|
327
|
+
"""
|
|
317
328
|
for name, value in (
|
|
318
329
|
("soft_timeout", soft_timeout),
|
|
319
330
|
("hard_timeout", hard_timeout),
|
|
320
331
|
):
|
|
332
|
+
if value is not None and value <= 0:
|
|
333
|
+
raise ValueError(f"{name} ({value}) must be greater than zero.")
|
|
321
334
|
if value is not None and value > MAX_TIMEOUT:
|
|
322
335
|
raise ValueError(
|
|
323
336
|
f"{name} ({value}) exceeds the maximum allowed value of {MAX_TIMEOUT} seconds."
|
|
324
337
|
)
|
|
338
|
+
|
|
325
339
|
if soft_timeout is not None and hard_timeout is not None:
|
|
326
340
|
if soft_timeout >= hard_timeout:
|
|
327
341
|
raise ValueError(
|
|
@@ -43,8 +43,7 @@ def handler(*, event: dict, context: object) -> dict:
|
|
|
43
43
|
).execute_immediately(message_id=record["messageId"])
|
|
44
44
|
except Exception:
|
|
45
45
|
logger.error(
|
|
46
|
-
"Failed to process SQS record
|
|
47
|
-
record.get("messageId"),
|
|
46
|
+
"Failed to process SQS record",
|
|
48
47
|
exc_info=True,
|
|
49
48
|
)
|
|
50
49
|
batch_item_failures.append({"itemIdentifier": record["messageId"]})
|
|
@@ -7,7 +7,7 @@ packages = ["lambda_tasks"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "django-lambda-tasks"
|
|
10
|
-
version = "0.1.
|
|
10
|
+
version = "0.1.5"
|
|
11
11
|
description = "Run async tasks in a lambda function"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
@@ -16,6 +16,7 @@ dependencies = [
|
|
|
16
16
|
"django",
|
|
17
17
|
"pydantic",
|
|
18
18
|
"redis",
|
|
19
|
+
"awslambdaric",
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
[dependency-groups]
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for timeout > 0 validation in decorators and resolved_timeouts.
|
|
3
|
+
|
|
4
|
+
Covers:
|
|
5
|
+
- Decorator-time rejection of zero and negative timeouts
|
|
6
|
+
- Settings-sourced rejection of zero and negative timeouts via resolved_timeouts
|
|
7
|
+
- Property-based: any positive timeout pair with soft < hard <= 900 is accepted
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from hypothesis import HealthCheck, given
|
|
12
|
+
from hypothesis import settings as h_settings
|
|
13
|
+
from hypothesis import strategies as st
|
|
14
|
+
|
|
15
|
+
from lambda_tasks.decorators import LambdaTaskWrapper
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _make_func():
|
|
19
|
+
def _task(*, x: int) -> None:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
return _task
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Decorator-time: zero timeouts rejected
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_soft_timeout_zero_raises_value_error():
|
|
31
|
+
"""soft_timeout=0 raises ValueError at decoration time."""
|
|
32
|
+
with pytest.raises(ValueError, match="soft_timeout"):
|
|
33
|
+
LambdaTaskWrapper(_make_func(), soft_timeout=0, hard_timeout=10)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_hard_timeout_zero_raises_value_error():
|
|
37
|
+
"""hard_timeout=0 raises ValueError at decoration time."""
|
|
38
|
+
with pytest.raises(ValueError, match="hard_timeout"):
|
|
39
|
+
LambdaTaskWrapper(_make_func(), soft_timeout=None, hard_timeout=0)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# Decorator-time: negative timeouts rejected
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_soft_timeout_negative_raises_value_error():
|
|
48
|
+
"""soft_timeout < 0 raises ValueError at decoration time."""
|
|
49
|
+
with pytest.raises(ValueError, match="soft_timeout"):
|
|
50
|
+
LambdaTaskWrapper(_make_func(), soft_timeout=-1, hard_timeout=10)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_hard_timeout_negative_raises_value_error():
|
|
54
|
+
"""hard_timeout < 0 raises ValueError at decoration time."""
|
|
55
|
+
with pytest.raises(ValueError, match="hard_timeout"):
|
|
56
|
+
LambdaTaskWrapper(_make_func(), hard_timeout=-5)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# Decorator-time: boundary — timeout=1 is the minimum accepted value
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_soft_timeout_one_is_accepted():
|
|
65
|
+
"""soft_timeout=1 is the minimum valid value."""
|
|
66
|
+
wrapper = LambdaTaskWrapper(_make_func(), soft_timeout=1, hard_timeout=2)
|
|
67
|
+
assert wrapper._soft_timeout == 1
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_hard_timeout_one_is_accepted():
|
|
71
|
+
"""hard_timeout=1 is the minimum valid value (soft left to settings)."""
|
|
72
|
+
wrapper = LambdaTaskWrapper(_make_func(), hard_timeout=1)
|
|
73
|
+
assert wrapper._hard_timeout == 1
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
# resolved_timeouts: settings-sourced zero rejected
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_resolved_soft_timeout_zero_from_settings_raises_value_error(settings):
|
|
82
|
+
"""soft_timeout=0 from settings raises ValueError on resolved_timeouts."""
|
|
83
|
+
settings.LAMBDA_TASKS_QUEUES = {"default": "https://sqs.example.com/default"}
|
|
84
|
+
settings.LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT = 0
|
|
85
|
+
settings.LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT = 300
|
|
86
|
+
|
|
87
|
+
wrapper = LambdaTaskWrapper(_make_func())
|
|
88
|
+
with pytest.raises(ValueError, match="soft_timeout"):
|
|
89
|
+
_ = wrapper.resolved_timeouts
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_resolved_hard_timeout_zero_from_settings_raises_value_error(settings):
|
|
93
|
+
"""hard_timeout=0 from settings raises ValueError on resolved_timeouts."""
|
|
94
|
+
settings.LAMBDA_TASKS_QUEUES = {"default": "https://sqs.example.com/default"}
|
|
95
|
+
settings.LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT = 0
|
|
96
|
+
settings.LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT = 0
|
|
97
|
+
|
|
98
|
+
wrapper = LambdaTaskWrapper(_make_func())
|
|
99
|
+
with pytest.raises(ValueError, match="timeout"):
|
|
100
|
+
_ = wrapper.resolved_timeouts
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
# resolved_timeouts: settings-sourced negative rejected
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_resolved_soft_timeout_negative_from_settings_raises_value_error(settings):
|
|
109
|
+
"""soft_timeout < 0 from settings raises ValueError on resolved_timeouts."""
|
|
110
|
+
settings.LAMBDA_TASKS_QUEUES = {"default": "https://sqs.example.com/default"}
|
|
111
|
+
settings.LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT = -10
|
|
112
|
+
settings.LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT = 300
|
|
113
|
+
|
|
114
|
+
wrapper = LambdaTaskWrapper(_make_func())
|
|
115
|
+
with pytest.raises(ValueError, match="soft_timeout"):
|
|
116
|
+
_ = wrapper.resolved_timeouts
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_resolved_hard_timeout_negative_from_settings_raises_value_error(settings):
|
|
120
|
+
"""hard_timeout < 0 from settings raises ValueError on resolved_timeouts."""
|
|
121
|
+
settings.LAMBDA_TASKS_QUEUES = {"default": "https://sqs.example.com/default"}
|
|
122
|
+
settings.LAMBDA_TASKS_DEFAULT_SOFT_TIMEOUT = -10
|
|
123
|
+
settings.LAMBDA_TASKS_DEFAULT_HARD_TIMEOUT = -5
|
|
124
|
+
|
|
125
|
+
wrapper = LambdaTaskWrapper(_make_func())
|
|
126
|
+
with pytest.raises(ValueError, match="timeout"):
|
|
127
|
+
_ = wrapper.resolved_timeouts
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# ---------------------------------------------------------------------------
|
|
131
|
+
# Property-based: valid timeout pairs (both > 0, soft < hard, hard <= 900)
|
|
132
|
+
# ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
_valid_timeout_pair = st.integers(min_value=1, max_value=899).flatmap(
|
|
136
|
+
lambda soft: st.integers(min_value=soft + 1, max_value=900).map(
|
|
137
|
+
lambda hard: (soft, hard)
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@given(timeout_pair=_valid_timeout_pair)
|
|
143
|
+
@h_settings(max_examples=100, suppress_health_check=[HealthCheck.too_slow])
|
|
144
|
+
def test_property_valid_timeout_pair_accepted(timeout_pair):
|
|
145
|
+
"""Any (soft, hard) with 1 <= soft < hard <= 900 is accepted at decoration time."""
|
|
146
|
+
soft, hard = timeout_pair
|
|
147
|
+
wrapper = LambdaTaskWrapper(_make_func(), soft_timeout=soft, hard_timeout=hard)
|
|
148
|
+
assert wrapper._soft_timeout == soft
|
|
149
|
+
assert wrapper._hard_timeout == hard
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
# Property-based: non-positive timeouts always rejected
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@given(value=st.integers(max_value=0))
|
|
158
|
+
@h_settings(max_examples=100, suppress_health_check=[HealthCheck.too_slow])
|
|
159
|
+
def test_property_non_positive_soft_timeout_rejected(value):
|
|
160
|
+
"""Any soft_timeout <= 0 raises ValueError at decoration time."""
|
|
161
|
+
with pytest.raises(ValueError):
|
|
162
|
+
LambdaTaskWrapper(_make_func(), soft_timeout=value, hard_timeout=10)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@given(value=st.integers(max_value=0))
|
|
166
|
+
@h_settings(max_examples=100, suppress_health_check=[HealthCheck.too_slow])
|
|
167
|
+
def test_property_non_positive_hard_timeout_rejected(value):
|
|
168
|
+
"""Any hard_timeout <= 0 raises ValueError at decoration time."""
|
|
169
|
+
with pytest.raises(ValueError):
|
|
170
|
+
LambdaTaskWrapper(_make_func(), hard_timeout=value)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/deferred-task-enqueue/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/eager-mode-example-app/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/.config.kiro
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/retry-delay/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/rse-background-tasks/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/.config.kiro
RENAMED
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/design.md
RENAMED
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/singleton-task/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/.kiro/specs/task-retry/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.1.4 → django_lambda_tasks-0.1.5}/lambda_tasks/migrations/0001_initial.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|