django-lambda-tasks 0.6.5__tar.gz → 0.6.6__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.5 → django_lambda_tasks-0.6.6}/.kiro/steering/product.md +1 -1
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/PKG-INFO +1 -1
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/handler.py +12 -17
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/pyproject.toml +1 -1
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_memory_limit.py +43 -59
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.github/workflows/ci.yml +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.github/workflows/release.yml +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.gitignore +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/eager-mode-example-app/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/eager-mode-example-app/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/eager-mode-example-app/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/eager-mode-example-app/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ignore-errors-decorator-option/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ignore-errors-decorator-option/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ignore-errors-decorator-option/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ignore-errors-decorator-option/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/import-string-task-resolution/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/import-string-task-resolution/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/import-string-task-resolution/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/import-string-task-resolution/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks-bugfix/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks-bugfix/bugfix.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks-bugfix/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks-bugfix/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/task-retry/.config.kiro +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/task-retry/design.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/task-retry/requirements.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/task-retry/tasks.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/steering/structure.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/steering/tech.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.pre-commit-config.yaml +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.vscode/settings.json +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/README.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/README.md +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_app/__init__.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_app/apps.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_app/tasks.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_app/urls.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_app/views.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_project/__init__.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_project/settings.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_project/urls.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/example_project/wsgi.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/example/manage.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/__init__.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/admin.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/apps.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/decorators.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/environment_loader.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/local_executor.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/logging.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/migrations/0001_initial.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/migrations/0002_alter_taskrecord_status.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/migrations/__init__.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/models.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/secret_loader.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/settings.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/tasks.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/lambda_tasks/timeouts.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/conftest.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/settings.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_admin.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_batch.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_batch_worker.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_decorator.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_decorators.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_deferred_enqueue.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_environment_loader.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_handler.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_kwargs_only.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_local_executor.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_logging.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_models.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_secret_loader.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_serializer.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_settings.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_tasks.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_timeout_validation.py +0 -0
- {django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/tests/test_timeouts.py +0 -0
|
@@ -151,7 +151,7 @@ class SQSLambdaTaskMessage(BaseModel):
|
|
|
151
151
|
- A module-level `_cold_start_done` sentinel ensures the sequence runs only once; subsequent warm invocations skip it
|
|
152
152
|
- Both loaders run unconditionally (outside the `DJANGO_SETTINGS_MODULE` check) — the environment secret may provide that var, and individual secrets may depend on environment-loaded vars
|
|
153
153
|
- A temporary `StreamHandler` is attached to the `lambda_tasks` logger for the duration of the loaders so their log output is visible before Django's `LOGGING` dictConfig has run; it is removed immediately after so that Django's configuration is the sole authority on logging from that point on
|
|
154
|
-
- `resource.setrlimit(
|
|
154
|
+
- `resource.setrlimit(RLIMIT_AS)` is set from `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` (Lambda) or the ECS task metadata endpoint (Fargate/Batch) so that excessive allocation raises `MemoryError` instead of triggering the OOM killer
|
|
155
155
|
|
|
156
156
|
`main()` in `handler.py` — AWS Batch container entry point (`python -m lambda_tasks.handler`):
|
|
157
157
|
- Reads `LAMBDA_TASKS_MESSAGE` env var (the serialized task JSON, set by `submit_batch_job` via container overrides)
|
|
@@ -12,12 +12,13 @@ timeouts. The sequence is guarded by a module-level sentinel so subsequent
|
|
|
12
12
|
warm invocations skip it.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
import json
|
|
15
16
|
import logging
|
|
16
17
|
import os
|
|
17
18
|
import resource
|
|
18
19
|
import sys
|
|
20
|
+
import urllib.request
|
|
19
21
|
import uuid
|
|
20
|
-
from pathlib import Path
|
|
21
22
|
|
|
22
23
|
import django
|
|
23
24
|
from django.apps import apps
|
|
@@ -32,37 +33,31 @@ _cold_start_done: bool = False
|
|
|
32
33
|
|
|
33
34
|
_MEMORY_RESERVED_MB = 128
|
|
34
35
|
_MEMORY_MINIMUM_LIMIT_MB = 64
|
|
35
|
-
_CGROUP_V2_MEMORY_MAX_PATH = Path("/sys/fs/cgroup/memory.max")
|
|
36
|
-
_CGROUP_V1_MEMORY_LIMIT_PATH = Path("/sys/fs/cgroup/memory/memory.limit_in_bytes")
|
|
37
36
|
|
|
38
37
|
|
|
39
38
|
def _get_memory_mb() -> int | None:
|
|
40
|
-
"""Get container memory limit from Lambda env var or
|
|
39
|
+
"""Get container memory limit from Lambda env var or ECS metadata endpoint."""
|
|
41
40
|
memory_mb_str = os.environ.get("AWS_LAMBDA_FUNCTION_MEMORY_SIZE")
|
|
42
41
|
if memory_mb_str is not None:
|
|
43
42
|
return int(memory_mb_str)
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
metadata_uri = os.environ.get("ECS_CONTAINER_METADATA_URI_V4")
|
|
45
|
+
if metadata_uri is not None:
|
|
46
|
+
try:
|
|
47
|
+
with urllib.request.urlopen(f"{metadata_uri}/task", timeout=2) as response:
|
|
48
|
+
data = json.loads(response.read())
|
|
49
|
+
return int(data["Limits"]["Memory"])
|
|
50
|
+
except Exception:
|
|
48
51
|
return None
|
|
49
|
-
else:
|
|
50
|
-
return int(value) // (1024 * 1024)
|
|
51
|
-
except (FileNotFoundError, ValueError):
|
|
52
|
-
pass
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
value = _CGROUP_V1_MEMORY_LIMIT_PATH.read_text().strip()
|
|
56
|
-
return int(value) // (1024 * 1024)
|
|
57
|
-
except (FileNotFoundError, ValueError):
|
|
58
|
-
return None
|
|
53
|
+
return None
|
|
59
54
|
|
|
60
55
|
|
|
61
56
|
def _set_memory_limit() -> None:
|
|
62
57
|
"""Set RLIMIT_AS from the container memory limit.
|
|
63
58
|
|
|
64
59
|
On Lambda, reads AWS_LAMBDA_FUNCTION_MEMORY_SIZE. On Fargate/Batch,
|
|
65
|
-
|
|
60
|
+
queries the ECS task metadata endpoint. This causes Python to raise
|
|
66
61
|
MemoryError on excessive allocation instead of being killed by the
|
|
67
62
|
OOM killer.
|
|
68
63
|
|
|
@@ -6,30 +6,18 @@ memory allocation raises MemoryError instead of triggering the Lambda OOM
|
|
|
6
6
|
killer.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import json
|
|
9
10
|
import resource
|
|
10
11
|
|
|
11
12
|
import lambda_tasks.handler as handler_module
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
class _FakePath:
|
|
15
|
-
def __init__(self, *, content: str | None) -> None:
|
|
16
|
-
self._content = content
|
|
17
|
-
|
|
18
|
-
def read_text(self) -> str:
|
|
19
|
-
if self._content is None:
|
|
20
|
-
raise FileNotFoundError
|
|
21
|
-
return self._content
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def fake_path(content: str | None) -> _FakePath:
|
|
25
|
-
return _FakePath(content=content)
|
|
26
|
-
|
|
27
|
-
|
|
28
15
|
class TestMemoryLimitSetDuringColdStart:
|
|
29
16
|
def test_rlimit_as_set_from_env_var(self, monkeypatch):
|
|
30
17
|
"""When AWS_LAMBDA_FUNCTION_MEMORY_SIZE is set, RLIMIT_AS is configured with 128 MB reserved."""
|
|
31
18
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
32
19
|
monkeypatch.setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "512")
|
|
20
|
+
monkeypatch.delenv("ECS_CONTAINER_METADATA_URI_V4", raising=False)
|
|
33
21
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
34
22
|
monkeypatch.setattr(
|
|
35
23
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
@@ -48,20 +36,15 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
48
36
|
expected = (512 - 128) * 1024 * 1024
|
|
49
37
|
assert calls == [(resource.RLIMIT_AS, (expected, expected))]
|
|
50
38
|
|
|
51
|
-
def
|
|
52
|
-
"""When
|
|
39
|
+
def test_rlimit_as_not_set_when_no_memory_source(self, monkeypatch):
|
|
40
|
+
"""When neither Lambda env var nor ECS metadata is available, RLIMIT_AS is unchanged."""
|
|
53
41
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
54
42
|
monkeypatch.delenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", raising=False)
|
|
43
|
+
monkeypatch.delenv("ECS_CONTAINER_METADATA_URI_V4", raising=False)
|
|
55
44
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
56
45
|
monkeypatch.setattr(
|
|
57
46
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
58
47
|
)
|
|
59
|
-
monkeypatch.setattr(
|
|
60
|
-
handler_module, "_CGROUP_V2_MEMORY_MAX_PATH", fake_path(None)
|
|
61
|
-
)
|
|
62
|
-
monkeypatch.setattr(
|
|
63
|
-
handler_module, "_CGROUP_V1_MEMORY_LIMIT_PATH", fake_path(None)
|
|
64
|
-
)
|
|
65
48
|
|
|
66
49
|
calls: list[tuple] = []
|
|
67
50
|
|
|
@@ -75,25 +58,33 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
75
58
|
|
|
76
59
|
assert calls == []
|
|
77
60
|
|
|
78
|
-
def
|
|
79
|
-
"""When
|
|
61
|
+
def test_rlimit_as_set_from_ecs_metadata(self, monkeypatch):
|
|
62
|
+
"""When ECS_CONTAINER_METADATA_URI_V4 is set, queries the task endpoint for memory."""
|
|
80
63
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
81
64
|
monkeypatch.delenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", raising=False)
|
|
65
|
+
monkeypatch.setenv("ECS_CONTAINER_METADATA_URI_V4", "http://169.254.170.2/v4")
|
|
82
66
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
83
67
|
monkeypatch.setattr(
|
|
84
68
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
85
69
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
70
|
+
|
|
71
|
+
task_metadata = json.dumps({"Limits": {"CPU": 2, "Memory": 8192}}).encode()
|
|
72
|
+
|
|
73
|
+
class FakeResponse:
|
|
74
|
+
def read(self):
|
|
75
|
+
return task_metadata
|
|
76
|
+
|
|
77
|
+
def __enter__(self):
|
|
78
|
+
return self
|
|
79
|
+
|
|
80
|
+
def __exit__(self, *args):
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def fake_urlopen(url, *, timeout=None):
|
|
84
|
+
assert url == "http://169.254.170.2/v4/task"
|
|
85
|
+
return FakeResponse()
|
|
86
|
+
|
|
87
|
+
monkeypatch.setattr("urllib.request.urlopen", fake_urlopen)
|
|
97
88
|
|
|
98
89
|
calls: list[tuple] = []
|
|
99
90
|
|
|
@@ -105,23 +96,23 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
105
96
|
handler_module._cold_start_done = False
|
|
106
97
|
handler_module.handler(event={"Records": []}, context=None)
|
|
107
98
|
|
|
108
|
-
expected = (
|
|
99
|
+
expected = (8192 - 128) * 1024 * 1024
|
|
109
100
|
assert calls == [(resource.RLIMIT_AS, (expected, expected))]
|
|
110
101
|
|
|
111
|
-
def
|
|
112
|
-
"""When
|
|
102
|
+
def test_rlimit_as_not_set_when_ecs_metadata_fails(self, monkeypatch):
|
|
103
|
+
"""When ECS metadata endpoint fails, RLIMIT_AS is unchanged."""
|
|
113
104
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
114
105
|
monkeypatch.delenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", raising=False)
|
|
106
|
+
monkeypatch.setenv("ECS_CONTAINER_METADATA_URI_V4", "http://169.254.170.2/v4")
|
|
115
107
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
116
108
|
monkeypatch.setattr(
|
|
117
109
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
118
110
|
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
111
|
+
|
|
112
|
+
def fake_urlopen(url, *, timeout=None):
|
|
113
|
+
raise OSError("connection refused")
|
|
114
|
+
|
|
115
|
+
monkeypatch.setattr("urllib.request.urlopen", fake_urlopen)
|
|
125
116
|
|
|
126
117
|
calls: list[tuple] = []
|
|
127
118
|
|
|
@@ -135,25 +126,15 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
135
126
|
|
|
136
127
|
assert calls == []
|
|
137
128
|
|
|
138
|
-
def
|
|
139
|
-
"""
|
|
129
|
+
def test_lambda_env_var_takes_precedence_over_ecs_metadata(self, monkeypatch):
|
|
130
|
+
"""AWS_LAMBDA_FUNCTION_MEMORY_SIZE is preferred over ECS metadata."""
|
|
140
131
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
141
|
-
monkeypatch.
|
|
132
|
+
monkeypatch.setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "512")
|
|
133
|
+
monkeypatch.setenv("ECS_CONTAINER_METADATA_URI_V4", "http://169.254.170.2/v4")
|
|
142
134
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
143
135
|
monkeypatch.setattr(
|
|
144
136
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
145
137
|
)
|
|
146
|
-
monkeypatch.setattr(
|
|
147
|
-
handler_module,
|
|
148
|
-
"_CGROUP_V2_MEMORY_MAX_PATH",
|
|
149
|
-
fake_path(None),
|
|
150
|
-
)
|
|
151
|
-
# 4 GB in bytes
|
|
152
|
-
monkeypatch.setattr(
|
|
153
|
-
handler_module,
|
|
154
|
-
"_CGROUP_V1_MEMORY_LIMIT_PATH",
|
|
155
|
-
fake_path(str(4096 * 1024 * 1024)),
|
|
156
|
-
)
|
|
157
138
|
|
|
158
139
|
calls: list[tuple] = []
|
|
159
140
|
|
|
@@ -165,13 +146,14 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
165
146
|
handler_module._cold_start_done = False
|
|
166
147
|
handler_module.handler(event={"Records": []}, context=None)
|
|
167
148
|
|
|
168
|
-
expected = (
|
|
149
|
+
expected = (512 - 128) * 1024 * 1024
|
|
169
150
|
assert calls == [(resource.RLIMIT_AS, (expected, expected))]
|
|
170
151
|
|
|
171
152
|
def test_memory_limit_set_before_loaders(self, monkeypatch):
|
|
172
153
|
"""The memory limit is set before resolve_environment runs."""
|
|
173
154
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
174
155
|
monkeypatch.setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "256")
|
|
156
|
+
monkeypatch.delenv("ECS_CONTAINER_METADATA_URI_V4", raising=False)
|
|
175
157
|
|
|
176
158
|
call_order: list[str] = []
|
|
177
159
|
|
|
@@ -207,6 +189,7 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
207
189
|
|
|
208
190
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
209
191
|
monkeypatch.setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "1024")
|
|
192
|
+
monkeypatch.delenv("ECS_CONTAINER_METADATA_URI_V4", raising=False)
|
|
210
193
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
211
194
|
monkeypatch.setattr(
|
|
212
195
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
@@ -224,6 +207,7 @@ class TestMemoryLimitSetDuringColdStart:
|
|
|
224
207
|
"""When AWS_LAMBDA_FUNCTION_MEMORY_SIZE <= reserved, RLIMIT_AS is set to the 64 MB minimum."""
|
|
225
208
|
monkeypatch.delenv("DJANGO_SETTINGS_MODULE", raising=False)
|
|
226
209
|
monkeypatch.setenv("AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "128")
|
|
210
|
+
monkeypatch.delenv("ECS_CONTAINER_METADATA_URI_V4", raising=False)
|
|
227
211
|
monkeypatch.setattr("lambda_tasks.handler.resolve_environment", lambda: None)
|
|
228
212
|
monkeypatch.setattr(
|
|
229
213
|
"lambda_tasks.handler.resolve_secrets_into_env", lambda: None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/async-local-execution/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/deferred-task-enqueue/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/eager-mode-example-app/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.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.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/.config.kiro
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/retry-delay/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/rse-background-tasks/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.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.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/.config.kiro
RENAMED
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/design.md
RENAMED
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/singleton-task/requirements.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/design.md
RENAMED
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.kiro/specs/ssm-environment-loader/tasks.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/.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
|
|
File without changes
|
{django_lambda_tasks-0.6.5 → django_lambda_tasks-0.6.6}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|