django-lambda-tasks 0.7.0__tar.gz → 0.8.1__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.7.0 → django_lambda_tasks-0.8.1}/.github/workflows/ci.yml +15 -1
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/PKG-INFO +5 -2
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/README.md +3 -0
- django_lambda_tasks-0.8.1/docker-compose.yml +11 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/README.md +12 -5
- django_lambda_tasks-0.8.1/example/docker-compose.yml +14 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_project/settings.py +7 -2
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/checks.py +21 -1
- django_lambda_tasks-0.8.1/lambda_tasks/migrations/0003_taskrecord_taskrecord_kwargs_trgm.py +29 -0
- django_lambda_tasks-0.8.1/lambda_tasks/migrations/0004_remove_taskrecord_taskrecord_kwargs_trgm_and_more.py +48 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/models.py +16 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/pyproject.toml +2 -1
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/settings.py +7 -2
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_admin.py +27 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_batch_worker.py +9 -0
- django_lambda_tasks-0.8.1/tests/test_checks.py +21 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_models.py +8 -1
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.github/workflows/release.yml +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.gitignore +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/eager-mode-example-app/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/eager-mode-example-app/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/eager-mode-example-app/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/eager-mode-example-app/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ignore-errors-decorator-option/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ignore-errors-decorator-option/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ignore-errors-decorator-option/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ignore-errors-decorator-option/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/import-string-task-resolution/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/import-string-task-resolution/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/import-string-task-resolution/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/import-string-task-resolution/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks-bugfix/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks-bugfix/bugfix.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks-bugfix/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks-bugfix/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/task-retry/.config.kiro +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/task-retry/design.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/task-retry/requirements.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/task-retry/tasks.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/steering/product.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/steering/structure.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/steering/tech.md +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.pre-commit-config.yaml +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.vscode/settings.json +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_app/__init__.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_app/apps.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_app/tasks.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_app/urls.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_app/views.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_project/__init__.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_project/urls.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/example_project/wsgi.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/example/manage.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/__init__.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/admin.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/apps.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/decorators.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/environment_loader.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/handler.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/local_executor.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/logging.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/migrations/0001_initial.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/migrations/0002_alter_taskrecord_status.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/migrations/__init__.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/secret_loader.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/settings.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/tasks.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/lambda_tasks/timeouts.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/conftest.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_batch.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_decorator.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_decorators.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_deferred_enqueue.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_environment_loader.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_handler.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_kwargs_only.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_local_executor.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_logging.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_memory_limit.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_noop_execution.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_secret_loader.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_serializer.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_settings.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_tasks.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_timeout_validation.py +0 -0
- {django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/tests/test_timeouts.py +0 -0
|
@@ -30,12 +30,26 @@ jobs:
|
|
|
30
30
|
strategy:
|
|
31
31
|
matrix:
|
|
32
32
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
33
|
+
services:
|
|
34
|
+
postgres:
|
|
35
|
+
image: postgres:17
|
|
36
|
+
env:
|
|
37
|
+
POSTGRES_DB: lambda_tasks_test
|
|
38
|
+
POSTGRES_USER: postgres
|
|
39
|
+
POSTGRES_PASSWORD: postgres
|
|
40
|
+
ports:
|
|
41
|
+
- 5432:5432
|
|
42
|
+
options: >-
|
|
43
|
+
--health-cmd "pg_isready -U postgres"
|
|
44
|
+
--health-interval 10s
|
|
45
|
+
--health-timeout 5s
|
|
46
|
+
--health-retries 5
|
|
33
47
|
steps:
|
|
34
48
|
- uses: actions/checkout@v4
|
|
35
49
|
- name: Install uv and set the python version
|
|
36
50
|
uses: astral-sh/setup-uv@v6
|
|
37
51
|
with:
|
|
38
52
|
python-version: ${{ matrix.python-version }}
|
|
39
|
-
- name: Run
|
|
53
|
+
- name: Run tests
|
|
40
54
|
run: |
|
|
41
55
|
uv run pytest --cov-branch --cov-report term-missing --cov=tests/ --cov=lambda_tasks/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: django-lambda-tasks
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: Run async tasks in a lambda function
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: awslambdaric
|
|
@@ -16,6 +16,8 @@ A Django library for offloading work to AWS Lambda or AWS Batch outside of the r
|
|
|
16
16
|
|
|
17
17
|
> **Platform note:** Unix-based systems only (Linux, macOS). Timeout enforcement relies on `SIGALRM`.
|
|
18
18
|
|
|
19
|
+
> **Database note:** PostgreSQL is required. The `TaskRecord` model uses PostgreSQL-specific features.
|
|
20
|
+
|
|
19
21
|
---
|
|
20
22
|
|
|
21
23
|
## Installation
|
|
@@ -90,6 +92,7 @@ A runnable Django project is included in the [`example/`](example/) directory. I
|
|
|
90
92
|
|
|
91
93
|
```bash
|
|
92
94
|
cd example
|
|
95
|
+
docker compose up -d
|
|
93
96
|
uv run python manage.py migrate
|
|
94
97
|
uv run python manage.py createsuperuser
|
|
95
98
|
uv run python manage.py runserver
|
|
@@ -4,6 +4,8 @@ A Django library for offloading work to AWS Lambda or AWS Batch outside of the r
|
|
|
4
4
|
|
|
5
5
|
> **Platform note:** Unix-based systems only (Linux, macOS). Timeout enforcement relies on `SIGALRM`.
|
|
6
6
|
|
|
7
|
+
> **Database note:** PostgreSQL is required. The `TaskRecord` model uses PostgreSQL-specific features.
|
|
8
|
+
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
## Installation
|
|
@@ -78,6 +80,7 @@ A runnable Django project is included in the [`example/`](example/) directory. I
|
|
|
78
80
|
|
|
79
81
|
```bash
|
|
80
82
|
cd example
|
|
83
|
+
docker compose up -d
|
|
81
84
|
uv run python manage.py migrate
|
|
82
85
|
uv run python manage.py createsuperuser
|
|
83
86
|
uv run python manage.py runserver
|
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
# Example App
|
|
2
2
|
|
|
3
|
-
A minimal Django app demonstrating `django-lambda-tasks` with `
|
|
3
|
+
A minimal Django app demonstrating `django-lambda-tasks` with `LAMBDA_TASKS_LOCAL_WORKERS = 2`. Tasks execute in a background process pool — no AWS infrastructure required.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
- `uv` installed
|
|
8
|
+
- Docker installed (for PostgreSQL)
|
|
8
9
|
- All commands run from the `example/` directory
|
|
9
10
|
|
|
10
11
|
## Setup
|
|
11
12
|
|
|
12
|
-
**1.
|
|
13
|
+
**1. Start PostgreSQL**
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
docker compose up -d
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**2. Apply migrations**
|
|
13
20
|
|
|
14
21
|
```bash
|
|
15
22
|
uv run python manage.py migrate
|
|
16
23
|
```
|
|
17
24
|
|
|
18
|
-
**
|
|
25
|
+
**3. Create a superuser** (to access the admin interface)
|
|
19
26
|
|
|
20
27
|
```bash
|
|
21
28
|
uv run python manage.py createsuperuser
|
|
22
29
|
```
|
|
23
30
|
|
|
24
|
-
**
|
|
31
|
+
**4. Start the development server**
|
|
25
32
|
|
|
26
33
|
```bash
|
|
27
34
|
uv run python manage.py runserver
|
|
@@ -33,7 +40,7 @@ uv run python manage.py runserver
|
|
|
33
40
|
|
|
34
41
|
Visit: `http://127.0.0.1:8000/trigger/?name=Alice`
|
|
35
42
|
|
|
36
|
-
The task runs
|
|
43
|
+
The task runs in a background worker process and the response confirms it was triggered.
|
|
37
44
|
|
|
38
45
|
**View task records in the admin**
|
|
39
46
|
|
|
@@ -17,6 +17,7 @@ INSTALLED_APPS = [
|
|
|
17
17
|
"django.contrib.sessions",
|
|
18
18
|
"django.contrib.messages",
|
|
19
19
|
"django.contrib.staticfiles",
|
|
20
|
+
"django.contrib.postgres",
|
|
20
21
|
"lambda_tasks",
|
|
21
22
|
"example_app",
|
|
22
23
|
]
|
|
@@ -53,8 +54,12 @@ WSGI_APPLICATION = "example_project.wsgi.application"
|
|
|
53
54
|
|
|
54
55
|
DATABASES = {
|
|
55
56
|
"default": {
|
|
56
|
-
"ENGINE": "django.db.backends.
|
|
57
|
-
"NAME":
|
|
57
|
+
"ENGINE": "django.db.backends.postgresql",
|
|
58
|
+
"NAME": "example",
|
|
59
|
+
"USER": "postgres",
|
|
60
|
+
"PASSWORD": "postgres",
|
|
61
|
+
"HOST": "localhost",
|
|
62
|
+
"PORT": "5432",
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
"""Django deployment checks for lambda_tasks."""
|
|
2
2
|
|
|
3
3
|
from django.conf import settings as django_settings
|
|
4
|
-
from django.core.checks import Warning, register
|
|
4
|
+
from django.core.checks import Error, Warning, register
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@register("lambda_tasks")
|
|
8
|
+
def check_contrib_postgres_installed(
|
|
9
|
+
*, app_configs: object, **kwargs: object
|
|
10
|
+
) -> list[Error]:
|
|
11
|
+
"""Error if django.contrib.postgres is not in INSTALLED_APPS."""
|
|
12
|
+
errors: list[Error] = []
|
|
13
|
+
|
|
14
|
+
if "django.contrib.postgres" not in django_settings.INSTALLED_APPS:
|
|
15
|
+
errors.append(
|
|
16
|
+
Error(
|
|
17
|
+
"django.contrib.postgres is not in INSTALLED_APPS.",
|
|
18
|
+
hint="Add 'django.contrib.postgres' to INSTALLED_APPS. "
|
|
19
|
+
"It is required for PostgreSQL-specific indexes used by lambda_tasks.",
|
|
20
|
+
id="lambda_tasks.E001",
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return errors
|
|
5
25
|
|
|
6
26
|
|
|
7
27
|
@register("lambda_tasks", deploy=True)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated by Django 6.0.3 on 2026-08-17 12:45
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.indexes
|
|
4
|
+
import django.db.models.functions.comparison
|
|
5
|
+
from django.contrib.postgres.operations import TrigramExtension
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
("lambda_tasks", "0002_alter_taskrecord_status"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
TrigramExtension(),
|
|
17
|
+
migrations.AddIndex(
|
|
18
|
+
model_name="taskrecord",
|
|
19
|
+
index=django.contrib.postgres.indexes.GinIndex(
|
|
20
|
+
django.contrib.postgres.indexes.OpClass(
|
|
21
|
+
django.db.models.functions.comparison.Cast(
|
|
22
|
+
"kwargs", output_field=models.TextField()
|
|
23
|
+
),
|
|
24
|
+
name="gin_trgm_ops",
|
|
25
|
+
),
|
|
26
|
+
name="taskrecord_kwargs_trgm",
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Generated by Django 6.0.3 on 2026-08-18 09:47
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.indexes
|
|
4
|
+
import django.db.models.functions.comparison
|
|
5
|
+
import django.db.models.functions.text
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
("lambda_tasks", "0003_taskrecord_taskrecord_kwargs_trgm"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.RemoveIndex(
|
|
17
|
+
model_name="taskrecord",
|
|
18
|
+
name="taskrecord_kwargs_trgm",
|
|
19
|
+
),
|
|
20
|
+
migrations.AddIndex(
|
|
21
|
+
model_name="taskrecord",
|
|
22
|
+
index=django.contrib.postgres.indexes.GinIndex(
|
|
23
|
+
django.contrib.postgres.indexes.OpClass(
|
|
24
|
+
django.db.models.functions.text.Upper(
|
|
25
|
+
django.db.models.functions.comparison.Cast(
|
|
26
|
+
"id", output_field=models.TextField()
|
|
27
|
+
)
|
|
28
|
+
),
|
|
29
|
+
name="gin_trgm_ops",
|
|
30
|
+
),
|
|
31
|
+
name="taskrecord_id_trgm",
|
|
32
|
+
),
|
|
33
|
+
),
|
|
34
|
+
migrations.AddIndex(
|
|
35
|
+
model_name="taskrecord",
|
|
36
|
+
index=django.contrib.postgres.indexes.GinIndex(
|
|
37
|
+
django.contrib.postgres.indexes.OpClass(
|
|
38
|
+
django.db.models.functions.text.Upper(
|
|
39
|
+
django.db.models.functions.comparison.Cast(
|
|
40
|
+
"kwargs", output_field=models.TextField()
|
|
41
|
+
)
|
|
42
|
+
),
|
|
43
|
+
name="gin_trgm_ops",
|
|
44
|
+
),
|
|
45
|
+
name="taskrecord_kwargs_trgm",
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
]
|
|
@@ -8,10 +8,12 @@ import traceback
|
|
|
8
8
|
import uuid
|
|
9
9
|
|
|
10
10
|
import boto3
|
|
11
|
+
from django.contrib.postgres.indexes import GinIndex, OpClass
|
|
11
12
|
from django.core.cache import caches
|
|
12
13
|
from django.core.exceptions import ImproperlyConfigured
|
|
13
14
|
from django.db import models, transaction
|
|
14
15
|
from django.db.models import Q
|
|
16
|
+
from django.db.models.functions import Cast, Upper
|
|
15
17
|
from django.utils.module_loading import import_string
|
|
16
18
|
from django.utils.timezone import now
|
|
17
19
|
from pydantic import BaseModel, ConfigDict, Field
|
|
@@ -74,6 +76,20 @@ class TaskRecord(models.Model):
|
|
|
74
76
|
models.Index(fields=["task_name"]),
|
|
75
77
|
models.Index(fields=["status"]),
|
|
76
78
|
models.Index(fields=["-start_time"]),
|
|
79
|
+
GinIndex(
|
|
80
|
+
OpClass(
|
|
81
|
+
Upper(Cast("id", output_field=models.TextField())),
|
|
82
|
+
name="gin_trgm_ops",
|
|
83
|
+
),
|
|
84
|
+
name="taskrecord_id_trgm",
|
|
85
|
+
),
|
|
86
|
+
GinIndex(
|
|
87
|
+
OpClass(
|
|
88
|
+
Upper(Cast("kwargs", output_field=models.TextField())),
|
|
89
|
+
name="gin_trgm_ops",
|
|
90
|
+
),
|
|
91
|
+
name="taskrecord_kwargs_trgm",
|
|
92
|
+
),
|
|
77
93
|
]
|
|
78
94
|
constraints = [
|
|
79
95
|
models.CheckConstraint(
|
|
@@ -7,7 +7,7 @@ packages = ["lambda_tasks"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "django-lambda-tasks"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.8.1"
|
|
11
11
|
description = "Run async tasks in a lambda function"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
@@ -30,6 +30,7 @@ dev = [
|
|
|
30
30
|
"pytest-xdist",
|
|
31
31
|
"pytest-cov",
|
|
32
32
|
"ty",
|
|
33
|
+
"psycopg",
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[tool.ty.rules]
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
DATABASES = {
|
|
2
2
|
"default": {
|
|
3
|
-
"ENGINE": "django.db.backends.
|
|
4
|
-
"NAME": "
|
|
3
|
+
"ENGINE": "django.db.backends.postgresql",
|
|
4
|
+
"NAME": "lambda_tasks_test",
|
|
5
|
+
"USER": "postgres",
|
|
6
|
+
"PASSWORD": "postgres",
|
|
7
|
+
"HOST": "localhost",
|
|
8
|
+
"PORT": "5432",
|
|
5
9
|
}
|
|
6
10
|
}
|
|
7
11
|
|
|
@@ -9,6 +13,7 @@ INSTALLED_APPS = [
|
|
|
9
13
|
"django.contrib.admin",
|
|
10
14
|
"django.contrib.contenttypes",
|
|
11
15
|
"django.contrib.auth",
|
|
16
|
+
"django.contrib.postgres",
|
|
12
17
|
"lambda_tasks",
|
|
13
18
|
]
|
|
14
19
|
|
|
@@ -281,3 +281,30 @@ class TestReplayAction:
|
|
|
281
281
|
|
|
282
282
|
action_names = list(model_admin.get_actions(request).keys())
|
|
283
283
|
assert "replay_tasks" in action_names
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@pytest.mark.django_db()
|
|
287
|
+
class TestKwargsSearchUsesIndex:
|
|
288
|
+
def test_admin_search_uses_gin_trigram_indexes(self) -> None:
|
|
289
|
+
"""Verify the GIN trigram indexes are used for admin search queries."""
|
|
290
|
+
from django.db import connection
|
|
291
|
+
from django.test import RequestFactory
|
|
292
|
+
|
|
293
|
+
model_admin = admin.site._registry[TaskRecord]
|
|
294
|
+
request = RequestFactory().get("/", data={"q": "29992d75"})
|
|
295
|
+
request.user = User(is_staff=True, is_superuser=True)
|
|
296
|
+
|
|
297
|
+
changelist = model_admin.get_changelist_instance(request)
|
|
298
|
+
queryset = changelist.get_queryset(request)
|
|
299
|
+
|
|
300
|
+
sql, params = queryset.query.sql_with_params()
|
|
301
|
+
with connection.cursor() as cursor:
|
|
302
|
+
cursor.execute("SET enable_seqscan = off")
|
|
303
|
+
cursor.execute("SET enable_indexscan = off")
|
|
304
|
+
cursor.execute(f"EXPLAIN {sql}", params)
|
|
305
|
+
plan = "\n".join(row[0] for row in cursor.fetchall())
|
|
306
|
+
cursor.execute("SET enable_indexscan = on")
|
|
307
|
+
cursor.execute("SET enable_seqscan = on")
|
|
308
|
+
|
|
309
|
+
assert "taskrecord_id_trgm" in plan
|
|
310
|
+
assert "taskrecord_kwargs_trgm" in plan
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Tests for lambda_tasks.batch_worker entry point."""
|
|
2
2
|
|
|
3
3
|
import uuid
|
|
4
|
+
from unittest.mock import patch
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
|
|
@@ -8,6 +9,14 @@ from lambda_tasks.decorators import lambda_task
|
|
|
8
9
|
from lambda_tasks.handler import main
|
|
9
10
|
from lambda_tasks.models import SQSLambdaTaskMessage, TaskRecord
|
|
10
11
|
|
|
12
|
+
|
|
13
|
+
@pytest.fixture(autouse=True)
|
|
14
|
+
def _patch_close_old_connections():
|
|
15
|
+
"""Prevent close_old_connections from closing the test DB connection."""
|
|
16
|
+
with patch("lambda_tasks.handler.db.close_old_connections"):
|
|
17
|
+
yield
|
|
18
|
+
|
|
19
|
+
|
|
11
20
|
QUEUES = {
|
|
12
21
|
"default": {"queue_url": "https://sqs.us-east-1.amazonaws.com/000000000000/default"}
|
|
13
22
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Tests for the django.contrib.postgres system check."""
|
|
2
|
+
|
|
3
|
+
from lambda_tasks.checks import check_contrib_postgres_installed
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_check_passes_when_contrib_postgres_installed(settings):
|
|
7
|
+
settings.INSTALLED_APPS = [
|
|
8
|
+
"django.contrib.postgres",
|
|
9
|
+
"lambda_tasks",
|
|
10
|
+
]
|
|
11
|
+
errors = check_contrib_postgres_installed(app_configs=None)
|
|
12
|
+
assert errors == []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_check_errors_when_contrib_postgres_missing(settings):
|
|
16
|
+
settings.INSTALLED_APPS = [
|
|
17
|
+
"lambda_tasks",
|
|
18
|
+
]
|
|
19
|
+
errors = check_contrib_postgres_installed(app_configs=None)
|
|
20
|
+
assert len(errors) == 1
|
|
21
|
+
assert errors[0].id == "lambda_tasks.E001"
|
|
@@ -1096,7 +1096,14 @@ def test_property_4_retry_increments_n_retries(n_retries, exc_type_name):
|
|
|
1096
1096
|
@pytest.mark.django_db(transaction=True)
|
|
1097
1097
|
@given(
|
|
1098
1098
|
x=st.integers(),
|
|
1099
|
-
label=st.text(
|
|
1099
|
+
label=st.text(
|
|
1100
|
+
min_size=1,
|
|
1101
|
+
max_size=20,
|
|
1102
|
+
alphabet=st.characters(
|
|
1103
|
+
blacklist_characters="\x00",
|
|
1104
|
+
blacklist_categories=("Cs",),
|
|
1105
|
+
),
|
|
1106
|
+
),
|
|
1100
1107
|
)
|
|
1101
1108
|
@h_settings(max_examples=50, suppress_health_check=[HealthCheck.too_slow])
|
|
1102
1109
|
def test_property_5_matching_exc_enqueues_retry_same_kwargs(x, label):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/async-local-execution/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/deferred-task-enqueue/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/eager-mode-example-app/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.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.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/.config.kiro
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/retry-delay/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/rse-background-tasks/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.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.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/.config.kiro
RENAMED
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/design.md
RENAMED
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/singleton-task/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.kiro/specs/ssm-environment-loader/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.7.0 → django_lambda_tasks-0.8.1}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|