simple-module-background-tasks 0.0.8__tar.gz → 0.0.10__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.
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/PKG-INFO +5 -5
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/module.py +6 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/sync_db.py +31 -3
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/pyproject.toml +5 -5
- simple_module_background_tasks-0.0.10/tests/test_sync_db.py +60 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/.gitignore +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/LICENSE +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/README.md +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/__init__.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/_signal_support.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/celery_app.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/constants.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/contracts/__init__.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/contracts/events.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/contracts/schemas.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/deps.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/endpoints/__init__.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/endpoints/api_admin.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/endpoints/views.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/locales/en.json +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/models.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/Detail.tsx +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/Index.tsx +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/Workers.tsx +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/components/ExecutionRow.tsx +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/components/RetryConfirmDialog.tsx +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/constants.ts +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/pages/retry.ts +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/py.typed +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/service.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/services.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/settings.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/signals.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/tasks.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/background_tasks/worker_inspector.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/package.json +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/conftest.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_admin_api.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_bg_service.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_signals.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_worker_inspector.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_workers_endpoints.py +0 -0
- {simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tsconfig.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simple_module_background_tasks
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.10
|
|
4
4
|
Summary: Celery + Redis task queue with admin UI for monitoring and retrying failed/stuck tasks
|
|
5
5
|
Project-URL: Homepage, https://github.com/antosubash/simple_module_python
|
|
6
6
|
Project-URL: Repository, https://github.com/antosubash/simple_module_python
|
|
@@ -23,10 +23,10 @@ Classifier: Typing :: Typed
|
|
|
23
23
|
Requires-Python: >=3.12
|
|
24
24
|
Requires-Dist: celery[redis]>=5.4
|
|
25
25
|
Requires-Dist: redis>=5
|
|
26
|
-
Requires-Dist: simple-module-core==0.0.
|
|
27
|
-
Requires-Dist: simple-module-db==0.0.
|
|
28
|
-
Requires-Dist: simple-module-hosting==0.0.
|
|
29
|
-
Requires-Dist: simple-module-settings==0.0.
|
|
26
|
+
Requires-Dist: simple-module-core==0.0.10
|
|
27
|
+
Requires-Dist: simple-module-db==0.0.10
|
|
28
|
+
Requires-Dist: simple-module-hosting==0.0.10
|
|
29
|
+
Requires-Dist: simple-module-settings==0.0.10
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
32
|
# simple_module_background_tasks
|
|
@@ -96,8 +96,14 @@ class BackgroundTasksModule(ModuleBase):
|
|
|
96
96
|
|
|
97
97
|
from background_tasks.celery_app import build_celery
|
|
98
98
|
from background_tasks.signals import bind_event_bus
|
|
99
|
+
from background_tasks.sync_db import set_database_url
|
|
99
100
|
|
|
100
101
|
services = app.state.background_tasks
|
|
102
|
+
# Pin the sync engine to the same URL the host's async settings
|
|
103
|
+
# resolved — pydantic-settings reads ``.env`` but never propagates
|
|
104
|
+
# to ``os.environ``, so signals would otherwise fall back to the
|
|
105
|
+
# SQLite default and silently drop ``TaskExecution`` rows.
|
|
106
|
+
set_database_url(app.state.sm.settings.database_url)
|
|
101
107
|
# build_celery imports `signals` for side effects and runs
|
|
102
108
|
# `autodiscover_tasks` across every installed module.
|
|
103
109
|
services.celery = build_celery(services.settings)
|
|
@@ -26,6 +26,7 @@ logger = logging.getLogger(__name__)
|
|
|
26
26
|
|
|
27
27
|
_engine: Engine | None = None
|
|
28
28
|
_session_factory: sessionmaker[Session] | None = None
|
|
29
|
+
_url_override: str | None = None
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def _sync_url(async_url: str) -> str:
|
|
@@ -37,9 +38,35 @@ def _sync_url(async_url: str) -> str:
|
|
|
37
38
|
return async_url.replace("+aiosqlite", "").replace("+asyncpg", "+psycopg2")
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
def set_database_url(url: str | None) -> None:
|
|
42
|
+
"""Pin the URL used to build the sync engine.
|
|
43
|
+
|
|
44
|
+
The web process loads ``.env`` via pydantic-settings, but those values
|
|
45
|
+
never land in ``os.environ`` — so reading ``SM_DATABASE_URL`` directly
|
|
46
|
+
from the env can silently drop us back to the SQLite default while the
|
|
47
|
+
rest of the app uses Postgres. ``BackgroundTasksModule.on_startup``
|
|
48
|
+
calls this with the resolved ``settings.database_url`` so signals use
|
|
49
|
+
the same DB the app is on. Pass ``None`` to clear the override (used in
|
|
50
|
+
tests + on shutdown).
|
|
51
|
+
"""
|
|
52
|
+
global _url_override, _engine, _session_factory
|
|
53
|
+
if _url_override == url:
|
|
54
|
+
return
|
|
55
|
+
_url_override = url
|
|
56
|
+
if _engine is not None:
|
|
57
|
+
_engine.dispose()
|
|
58
|
+
_engine = None
|
|
59
|
+
_session_factory = None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _resolve_url() -> str:
|
|
63
|
+
if _url_override is not None:
|
|
64
|
+
return _url_override
|
|
65
|
+
return os.environ.get("SM_DATABASE_URL", "sqlite:///./app.db")
|
|
66
|
+
|
|
67
|
+
|
|
40
68
|
def _build_engine() -> Engine:
|
|
41
|
-
|
|
42
|
-
sync_url = _sync_url(url)
|
|
69
|
+
sync_url = _sync_url(_resolve_url())
|
|
43
70
|
# Small pool — signals fire sequentially per worker process.
|
|
44
71
|
return create_engine(sync_url, pool_pre_ping=True, pool_size=2, max_overflow=3)
|
|
45
72
|
|
|
@@ -60,11 +87,12 @@ def dispose_sync_engine() -> None:
|
|
|
60
87
|
restarts within one process (test runners, uvicorn dev reload) don't
|
|
61
88
|
accumulate engines against the old DB URL.
|
|
62
89
|
"""
|
|
63
|
-
global _engine, _session_factory
|
|
90
|
+
global _engine, _session_factory, _url_override
|
|
64
91
|
if _engine is not None:
|
|
65
92
|
_engine.dispose()
|
|
66
93
|
_engine = None
|
|
67
94
|
_session_factory = None
|
|
95
|
+
_url_override = None
|
|
68
96
|
|
|
69
97
|
|
|
70
98
|
@contextmanager
|
{simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/pyproject.toml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "simple_module_background_tasks"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.10"
|
|
4
4
|
description = "Celery + Redis task queue with admin UI for monitoring and retrying failed/stuck tasks"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -21,10 +21,10 @@ classifiers = [
|
|
|
21
21
|
"Typing :: Typed",
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"simple_module_core==0.0.
|
|
25
|
-
"simple_module_db==0.0.
|
|
26
|
-
"simple_module_hosting==0.0.
|
|
27
|
-
"simple_module_settings==0.0.
|
|
24
|
+
"simple_module_core==0.0.10",
|
|
25
|
+
"simple_module_db==0.0.10",
|
|
26
|
+
"simple_module_hosting==0.0.10",
|
|
27
|
+
"simple_module_settings==0.0.10",
|
|
28
28
|
"celery[redis]>=5.4",
|
|
29
29
|
"redis>=5",
|
|
30
30
|
]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Tests for the sync session factory's URL resolution.
|
|
2
|
+
|
|
3
|
+
The web process loads ``.env`` via pydantic-settings but never propagates the
|
|
4
|
+
result to ``os.environ``. ``set_database_url`` lets the module's
|
|
5
|
+
``on_startup`` pin the sync engine to whatever the host settings resolved,
|
|
6
|
+
so signals don't silently fall back to SQLite while the rest of the app
|
|
7
|
+
talks to Postgres.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Iterator
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
from background_tasks import sync_db
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture(autouse=True)
|
|
19
|
+
def _reset_sync_db() -> Iterator[None]:
|
|
20
|
+
sync_db.dispose_sync_engine()
|
|
21
|
+
yield
|
|
22
|
+
sync_db.dispose_sync_engine()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_resolve_url_falls_back_to_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
26
|
+
monkeypatch.setenv("SM_DATABASE_URL", "sqlite:///./from-env.db")
|
|
27
|
+
sync_db.set_database_url(None)
|
|
28
|
+
|
|
29
|
+
assert sync_db._resolve_url() == "sqlite:///./from-env.db"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_set_database_url_overrides_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
33
|
+
monkeypatch.setenv("SM_DATABASE_URL", "sqlite:///./from-env.db")
|
|
34
|
+
sync_db.set_database_url("postgresql+asyncpg://u:p@h/db")
|
|
35
|
+
|
|
36
|
+
assert sync_db._resolve_url() == "postgresql+asyncpg://u:p@h/db"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_set_database_url_resets_engine_when_url_changes(tmp_path) -> None:
|
|
40
|
+
db_a = tmp_path / "a.db"
|
|
41
|
+
db_b = tmp_path / "b.db"
|
|
42
|
+
sync_db.set_database_url(f"sqlite:///{db_a}")
|
|
43
|
+
factory_a = sync_db.get_sync_session_factory()
|
|
44
|
+
sync_db.set_database_url(f"sqlite:///{db_a}")
|
|
45
|
+
factory_a_again = sync_db.get_sync_session_factory()
|
|
46
|
+
assert factory_a is factory_a_again, "same URL must reuse the cached factory"
|
|
47
|
+
|
|
48
|
+
sync_db.set_database_url(f"sqlite:///{db_b}")
|
|
49
|
+
factory_b = sync_db.get_sync_session_factory()
|
|
50
|
+
assert factory_b is not factory_a, "URL change must dispose the old engine"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_dispose_sync_engine_clears_url_override(tmp_path) -> None:
|
|
54
|
+
url = f"sqlite:///{tmp_path / 'pinned.db'}"
|
|
55
|
+
sync_db.set_database_url(url)
|
|
56
|
+
assert sync_db._url_override == url
|
|
57
|
+
|
|
58
|
+
sync_db.dispose_sync_engine()
|
|
59
|
+
|
|
60
|
+
assert sync_db._url_override is None
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tests/test_signals.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_module_background_tasks-0.0.8 → simple_module_background_tasks-0.0.10}/tsconfig.json
RENAMED
|
File without changes
|