celery-manager 0.1.0a2__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.
- celery_manager-0.1.0a2/.gitignore +42 -0
- celery_manager-0.1.0a2/CHANGELOG.md +325 -0
- celery_manager-0.1.0a2/LICENSE +21 -0
- celery_manager-0.1.0a2/PKG-INFO +225 -0
- celery_manager-0.1.0a2/README.md +172 -0
- celery_manager-0.1.0a2/docs/assets/logo-wordmark-dark.svg +1 -0
- celery_manager-0.1.0a2/docs/assets/logo-wordmark-light.svg +1 -0
- celery_manager-0.1.0a2/docs/assets/logo.svg +1 -0
- celery_manager-0.1.0a2/docs/assets/social-preview.png +0 -0
- celery_manager-0.1.0a2/docs/configuration.md +208 -0
- celery_manager-0.1.0a2/docs/contributing.md +104 -0
- celery_manager-0.1.0a2/docs/dashboard.md +340 -0
- celery_manager-0.1.0a2/docs/decorator.md +275 -0
- celery_manager-0.1.0a2/docs/index.md +68 -0
- celery_manager-0.1.0a2/docs/integrations.md +176 -0
- celery_manager-0.1.0a2/docs/progress.md +186 -0
- celery_manager-0.1.0a2/docs/quickstart.md +211 -0
- celery_manager-0.1.0a2/docs/rest-api.md +428 -0
- celery_manager-0.1.0a2/examples/django_demo/.gitignore +6 -0
- celery_manager-0.1.0a2/examples/django_demo/README.md +203 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/__init__.py +3 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/asgi.py +16 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/celery.py +15 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/settings.py +174 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/urls.py +27 -0
- celery_manager-0.1.0a2/examples/django_demo/demo/wsgi.py +16 -0
- celery_manager-0.1.0a2/examples/django_demo/manage.py +22 -0
- celery_manager-0.1.0a2/examples/django_demo/requirements.txt +7 -0
- celery_manager-0.1.0a2/examples/django_demo/run_dashboard.py +25 -0
- celery_manager-0.1.0a2/examples/django_demo/tasks_app/__init__.py +0 -0
- celery_manager-0.1.0a2/examples/django_demo/tasks_app/apps.py +6 -0
- celery_manager-0.1.0a2/examples/django_demo/tasks_app/tasks.py +89 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/README.md +60 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/celery_app.py +27 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/create_user.py +19 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/main.py +42 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/requirements.txt +7 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/settings.py +40 -0
- celery_manager-0.1.0a2/examples/fastapi_demo/tasks.py +46 -0
- celery_manager-0.1.0a2/examples/flask_demo/README.md +64 -0
- celery_manager-0.1.0a2/examples/flask_demo/app.py +66 -0
- celery_manager-0.1.0a2/examples/flask_demo/celery_app.py +27 -0
- celery_manager-0.1.0a2/examples/flask_demo/create_user.py +19 -0
- celery_manager-0.1.0a2/examples/flask_demo/requirements.txt +8 -0
- celery_manager-0.1.0a2/examples/flask_demo/settings.py +40 -0
- celery_manager-0.1.0a2/examples/flask_demo/tasks.py +46 -0
- celery_manager-0.1.0a2/frontend/.gitignore +24 -0
- celery_manager-0.1.0a2/frontend/.oxlintrc.json +8 -0
- celery_manager-0.1.0a2/frontend/README.md +86 -0
- celery_manager-0.1.0a2/frontend/index.html +41 -0
- celery_manager-0.1.0a2/frontend/package-lock.json +2442 -0
- celery_manager-0.1.0a2/frontend/package.json +31 -0
- celery_manager-0.1.0a2/frontend/postcss.config.js +6 -0
- celery_manager-0.1.0a2/frontend/public/favicon.svg +4 -0
- celery_manager-0.1.0a2/frontend/src/App.tsx +194 -0
- celery_manager-0.1.0a2/frontend/src/api/audit.ts +16 -0
- celery_manager-0.1.0a2/frontend/src/api/base.ts +10 -0
- celery_manager-0.1.0a2/frontend/src/api/client.ts +43 -0
- celery_manager-0.1.0a2/frontend/src/api/schedules.ts +57 -0
- celery_manager-0.1.0a2/frontend/src/api/settings.ts +103 -0
- celery_manager-0.1.0a2/frontend/src/api/tasks.ts +133 -0
- celery_manager-0.1.0a2/frontend/src/branding.tsx +382 -0
- celery_manager-0.1.0a2/frontend/src/lib/taskProgress.ts +147 -0
- celery_manager-0.1.0a2/frontend/src/main.tsx +26 -0
- celery_manager-0.1.0a2/frontend/src/pages/AuditLog.tsx +97 -0
- celery_manager-0.1.0a2/frontend/src/pages/Login.tsx +90 -0
- celery_manager-0.1.0a2/frontend/src/pages/ScheduleList.tsx +84 -0
- celery_manager-0.1.0a2/frontend/src/pages/ScheduleOccurrences.tsx +197 -0
- celery_manager-0.1.0a2/frontend/src/pages/Settings.tsx +369 -0
- celery_manager-0.1.0a2/frontend/src/pages/TaskDetail.tsx +695 -0
- celery_manager-0.1.0a2/frontend/src/pages/TaskList.tsx +1208 -0
- celery_manager-0.1.0a2/frontend/src/styles/task-detail.css +427 -0
- celery_manager-0.1.0a2/frontend/src/styles/tasks.css +794 -0
- celery_manager-0.1.0a2/frontend/src/styles/tokens.css +2139 -0
- celery_manager-0.1.0a2/frontend/src/theme.ts +167 -0
- celery_manager-0.1.0a2/frontend/tailwind.config.ts +22 -0
- celery_manager-0.1.0a2/frontend/tsconfig.app.json +26 -0
- celery_manager-0.1.0a2/frontend/tsconfig.json +7 -0
- celery_manager-0.1.0a2/frontend/tsconfig.node.json +23 -0
- celery_manager-0.1.0a2/frontend/vite.config.ts +10 -0
- celery_manager-0.1.0a2/mkdocs.yml +37 -0
- celery_manager-0.1.0a2/pyproject.toml +99 -0
- celery_manager-0.1.0a2/src/celery_manager/__init__.py +47 -0
- celery_manager-0.1.0a2/src/celery_manager/api/__init__.py +0 -0
- celery_manager-0.1.0a2/src/celery_manager/api/app.py +83 -0
- celery_manager-0.1.0a2/src/celery_manager/api/deps.py +34 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/__init__.py +0 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/audit.py +42 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/auth.py +55 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/schedules.py +72 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/settings.py +83 -0
- celery_manager-0.1.0a2/src/celery_manager/api/routes/tasks.py +204 -0
- celery_manager-0.1.0a2/src/celery_manager/api/security.py +143 -0
- celery_manager-0.1.0a2/src/celery_manager/api/serialization.py +55 -0
- celery_manager-0.1.0a2/src/celery_manager/api/sse.py +89 -0
- celery_manager-0.1.0a2/src/celery_manager/auth/__init__.py +0 -0
- celery_manager-0.1.0a2/src/celery_manager/auth/sessions.py +19 -0
- celery_manager-0.1.0a2/src/celery_manager/auth/users.py +51 -0
- celery_manager-0.1.0a2/src/celery_manager/cli.py +46 -0
- celery_manager-0.1.0a2/src/celery_manager/config.py +38 -0
- celery_manager-0.1.0a2/src/celery_manager/control/__init__.py +55 -0
- celery_manager-0.1.0a2/src/celery_manager/control/audit.py +20 -0
- celery_manager-0.1.0a2/src/celery_manager/control/schedules.py +271 -0
- celery_manager-0.1.0a2/src/celery_manager/control/settings.py +266 -0
- celery_manager-0.1.0a2/src/celery_manager/control/tasks.py +319 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/__init__.py +6 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-700-normal-Bth3BMcD.woff +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/ibm-plex-sans-latin-700-normal-Bxkt5Cjx.woff2 +0 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/index-AUSbcb6p.js +11 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/assets/index-CzsGQV47.css +1 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/favicon.svg +4 -0
- celery_manager-0.1.0a2/src/celery_manager/dashboard/static/index.html +42 -0
- celery_manager-0.1.0a2/src/celery_manager/db/__init__.py +0 -0
- celery_manager-0.1.0a2/src/celery_manager/db/models.py +124 -0
- celery_manager-0.1.0a2/src/celery_manager/db/session.py +34 -0
- celery_manager-0.1.0a2/src/celery_manager/decorator.py +451 -0
- celery_manager-0.1.0a2/src/celery_manager/events/__init__.py +0 -0
- celery_manager-0.1.0a2/src/celery_manager/events/listener.py +104 -0
- celery_manager-0.1.0a2/src/celery_manager/logcapture.py +19 -0
- celery_manager-0.1.0a2/src/celery_manager/progress.py +321 -0
- celery_manager-0.1.0a2/src/celery_manager/runtime.py +54 -0
- celery_manager-0.1.0a2/tests/__init__.py +0 -0
- celery_manager-0.1.0a2/tests/integration/__init__.py +0 -0
- celery_manager-0.1.0a2/tests/integration/test_mounting.py +153 -0
- celery_manager-0.1.0a2/tests/unit/__init__.py +0 -0
- celery_manager-0.1.0a2/tests/unit/test_api_audit.py +65 -0
- celery_manager-0.1.0a2/tests/unit/test_api_auth.py +201 -0
- celery_manager-0.1.0a2/tests/unit/test_api_schedules.py +186 -0
- celery_manager-0.1.0a2/tests/unit/test_api_security.py +153 -0
- celery_manager-0.1.0a2/tests/unit/test_api_settings.py +358 -0
- celery_manager-0.1.0a2/tests/unit/test_api_sse.py +251 -0
- celery_manager-0.1.0a2/tests/unit/test_api_tasks.py +452 -0
- celery_manager-0.1.0a2/tests/unit/test_auth.py +109 -0
- celery_manager-0.1.0a2/tests/unit/test_cli.py +38 -0
- celery_manager-0.1.0a2/tests/unit/test_control_retry_audit.py +246 -0
- celery_manager-0.1.0a2/tests/unit/test_control_schedules.py +327 -0
- celery_manager-0.1.0a2/tests/unit/test_control_tasks.py +260 -0
- celery_manager-0.1.0a2/tests/unit/test_decorator.py +642 -0
- celery_manager-0.1.0a2/tests/unit/test_events_listener.py +175 -0
- celery_manager-0.1.0a2/tests/unit/test_models.py +64 -0
- celery_manager-0.1.0a2/tests/unit/test_progress.py +434 -0
- celery_manager-0.1.0a2/tests/unit/test_setup.py +109 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
.venv/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
celery_manager.db
|
|
8
|
+
frontend/node_modules/
|
|
9
|
+
frontend/dist/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Browser-automation output from UI verification runs (screenshots,
|
|
14
|
+
# accessibility snapshots, console logs). Regenerated on demand; never a
|
|
15
|
+
# deliverable.
|
|
16
|
+
.playwright-mcp/
|
|
17
|
+
|
|
18
|
+
# MkDocs build output — the docs site is built from docs/ on demand.
|
|
19
|
+
site/
|
|
20
|
+
|
|
21
|
+
# macOS Finder metadata. Ignored here rather than relying on every
|
|
22
|
+
# contributor having it in their global excludes.
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# Dependency / tool caches
|
|
26
|
+
node_modules/
|
|
27
|
+
.ruff_cache/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
.coverage
|
|
30
|
+
htmlcov/
|
|
31
|
+
|
|
32
|
+
# Local-only assistant/tooling state
|
|
33
|
+
.superpowers/
|
|
34
|
+
|
|
35
|
+
# Demo databases
|
|
36
|
+
*.db
|
|
37
|
+
*.sqlite
|
|
38
|
+
*.sqlite3
|
|
39
|
+
*.db-journal
|
|
40
|
+
*.db-wal
|
|
41
|
+
*.db-shm
|
|
42
|
+
.env
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to celery-manager are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0a2] — 2026-10-25
|
|
8
|
+
|
|
9
|
+
The first release published to PyPI (`pip install --pre celery-manager`).
|
|
10
|
+
There are no code changes since 0.1.0a1 apart from the version string.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- README and package metadata are PyPI-ready: every link and image in the
|
|
15
|
+
README is now absolute, so it renders on pypi.org.
|
|
16
|
+
- Install instructions lead with `pip install --pre celery-manager`; the git-tag
|
|
17
|
+
install remains as an alternative.
|
|
18
|
+
- Added a `Changelog` project URL; the GitHub account casing is now
|
|
19
|
+
`Pythondeveloper6` everywhere.
|
|
20
|
+
- `SECURITY.md` updated for the now-public repository.
|
|
21
|
+
|
|
22
|
+
## [0.1.0a1] — 2026-10-25
|
|
23
|
+
|
|
24
|
+
The initial release. Before this alpha, celery-manager had never been published, so everything
|
|
25
|
+
below is new rather than changed — with a few exceptions, called out first
|
|
26
|
+
because anyone who pinned a git SHA during development *will* hit them.
|
|
27
|
+
|
|
28
|
+
### Breaking
|
|
29
|
+
|
|
30
|
+
- **`GET /api/tasks` now returns an envelope, not a bare array.** It used to
|
|
31
|
+
return a JSON array of runs, hard-capped at 50 rows, with no `offset` — so
|
|
32
|
+
older history was unreachable and a client could not tell "50 results" from
|
|
33
|
+
"the first 50 of 1,284". It now returns:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{"items": [ ... ], "total": 1284, "limit": 50, "offset": 0}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Callers must change `res.json()` to `res.json().items`. The items also
|
|
40
|
+
gained `runtime_seconds` and the four `progress_*` fields. There is no
|
|
41
|
+
compatibility shim and no version negotiation: the change was taken
|
|
42
|
+
deliberately while the package was unreleased and its only consumers were
|
|
43
|
+
the bundled dashboard and `docs/rest-api.md`. See
|
|
44
|
+
[the REST API reference](docs/rest-api.md#tasks).
|
|
45
|
+
- **The session cookie is now `cm_session`, and `create_app()` refuses a
|
|
46
|
+
default `secret_key`.** Both are security fixes; see [Security](#security)
|
|
47
|
+
below for what changed and what you need to do.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
**Task history, search and filtering**
|
|
52
|
+
|
|
53
|
+
- `GET /api/tasks` gained `q`, `date_from`, `date_to`, `limit` and `offset`
|
|
54
|
+
alongside the existing `status` and `task_name`. `limit` is clamped into
|
|
55
|
+
`1..500` (`control.tasks.MAX_PAGE_SIZE`) rather than rejected, and the
|
|
56
|
+
clamped values are echoed back in the envelope.
|
|
57
|
+
- `q` is a case-insensitive substring search OR-ed across `task_name`,
|
|
58
|
+
`task_id`, `args` and `kwargs`. Because args/kwargs are stored as
|
|
59
|
+
serialized JSON text, this searches that text — there is no way to express
|
|
60
|
+
`kwargs.user == "alice"`. LIKE wildcards in the search term are escaped, so
|
|
61
|
+
`q=100%` finds a literal `100%` instead of matching every row.
|
|
62
|
+
- Both date bounds apply to `started_at` and are inclusive, which means a
|
|
63
|
+
queued run (no `started_at`) is excluded by either bound, and `date_to` is
|
|
64
|
+
an instant rather than a calendar day.
|
|
65
|
+
- `control.count_task_runs()` — the total behind "showing 50 of 1,284". It
|
|
66
|
+
shares one filter builder with `list_task_runs()`, so a total can never be
|
|
67
|
+
a count of a different query than the page it labels.
|
|
68
|
+
|
|
69
|
+
**Live progress**
|
|
70
|
+
|
|
71
|
+
- `celery_manager.report_progress(current, total=None, message=None)`, called
|
|
72
|
+
from inside a task body. Writes `progress_current`, `progress_total`,
|
|
73
|
+
`progress_message` and `progress_updated_at` on the run's `task_runs` row
|
|
74
|
+
while the task is still in flight; all four are served raw by both task
|
|
75
|
+
endpoints so the client decides how to render them.
|
|
76
|
+
- Database writes are throttled to one per 0.5 s per run
|
|
77
|
+
(`progress.MIN_WRITE_INTERVAL_SECONDS`), so it is safe in a tight loop. The
|
|
78
|
+
completing call (`current >= total`) bypasses the throttle, so a finished
|
|
79
|
+
task never sits at 99%.
|
|
80
|
+
- Omitting `total` means open-ended progress: a count and a message, no
|
|
81
|
+
percentage. A `total` of 0, negative, or non-int-able is treated the same
|
|
82
|
+
way — celery-manager never invents a denominator.
|
|
83
|
+
- Never raises into the calling task, and never blocks it: bad arguments are
|
|
84
|
+
ignored, a missing task context or an unwired process each log one WARNING
|
|
85
|
+
per process and return.
|
|
86
|
+
- Works on undecorated tasks too, via `celery.current_task`.
|
|
87
|
+
|
|
88
|
+
**Retry lineage**
|
|
89
|
+
|
|
90
|
+
- `task_runs.retried_from_id`, stamped by `retry_task()` on the run it
|
|
91
|
+
dispatches, so the chain is visible immediately rather than whenever the
|
|
92
|
+
events listener catches up.
|
|
93
|
+
- `control.list_retries_of()` and the `retried_from_id` / `retried_by` fields
|
|
94
|
+
on `GET /api/tasks/{task_id}`. `retried_by` is a list — retrying the same
|
|
95
|
+
failed run more than once is normal, and each attempt is its own run.
|
|
96
|
+
|
|
97
|
+
**Branding settings**
|
|
98
|
+
|
|
99
|
+
- `GET` / `PUT /api/settings` and the `app_settings` table, holding exactly
|
|
100
|
+
three keys: `brand_name`, `brand_accent`, `brand_logo_url`. Deployment-wide,
|
|
101
|
+
not per-browser.
|
|
102
|
+
- **`GET /api/settings` is deliberately unauthenticated** — the login screen
|
|
103
|
+
has to render the deployment's branding, and the login screen is pre-auth.
|
|
104
|
+
That is safe only because `DEFAULT_SETTINGS` is a closed allowlist of
|
|
105
|
+
non-sensitive values; `updated_by`/`updated_at` are deliberately not
|
|
106
|
+
returned. Treat adding a key to that dict as a security decision.
|
|
107
|
+
- Values are validated strictly and rejected with a `422` carrying a
|
|
108
|
+
human-readable reason: the accent is an anchored hex allowlist (it lands in
|
|
109
|
+
a CSS custom property), and the logo URL is a scheme allowlist that refuses
|
|
110
|
+
SVG data URIs (it lands in an `<img src>`).
|
|
111
|
+
- Any authenticated user can rebrand — there is no role system in v1 — but
|
|
112
|
+
every changed key writes an audit row with old and new values.
|
|
113
|
+
- `control.get_settings()` / `control.update_settings()` for the same
|
|
114
|
+
operations from Python.
|
|
115
|
+
|
|
116
|
+
**Task detail depth**
|
|
117
|
+
|
|
118
|
+
- `GET /api/tasks/{task_id}` gained `queue`, `worker`, `eta`, `started_at`,
|
|
119
|
+
`finished_at`, `runtime_seconds` and the four `progress_*` fields. (`eta`
|
|
120
|
+
is served but nothing currently writes it — see the note in the REST API
|
|
121
|
+
reference.)
|
|
122
|
+
|
|
123
|
+
**Dashboard**
|
|
124
|
+
|
|
125
|
+
- Task list rebuilt around a left filter panel (search, status, group-by,
|
|
126
|
+
collapsible date range) with removable active-filter chips, repeated in the
|
|
127
|
+
empty state so an empty table says which filter emptied it. The panel
|
|
128
|
+
collapses behind a **Filters** toggle below ~1024px.
|
|
129
|
+
- Two explicit modes: **live** (polls every 5 s, **Load more** widens the
|
|
130
|
+
page up to the 500-row ceiling) and **history** (explicit offset paging
|
|
131
|
+
through the full filtered total, polling switched off so rows can't shift
|
|
132
|
+
under you between clicks), with a **Back to live** bar.
|
|
133
|
+
- Per-row progress bars with percentage, message and a projected time
|
|
134
|
+
remaining; a run that has stopped reporting says how long it has been quiet
|
|
135
|
+
and drops the estimate rather than counting down as if nothing were wrong.
|
|
136
|
+
- Task detail gained a Run panel (progress, live elapsed, estimated finish),
|
|
137
|
+
an Execution panel (worker, queue, ETA, timings, each with a reason rather
|
|
138
|
+
than a blank cell), and a retry-lineage panel walking the chain in both
|
|
139
|
+
directions.
|
|
140
|
+
- Light / dark / **system** theming as an explicit per-browser choice, stored
|
|
141
|
+
in local storage, applied before first paint and synced across tabs.
|
|
142
|
+
- A branding settings screen with a live preview and a measured contrast
|
|
143
|
+
readout for the accent colour.
|
|
144
|
+
- Dashboard: sign-out control in the nav.
|
|
145
|
+
- Dashboard: Cancel and Terminate controls on the task detail page (terminate asks for inline confirmation)
|
|
146
|
+
|
|
147
|
+
**Framework integration**
|
|
148
|
+
|
|
149
|
+
- Mount the dashboard under a prefix inside a FastAPI app
|
|
150
|
+
(`app.mount("/celery-manager", dashboard)`) or a Flask app (via `a2wsgi`
|
|
151
|
+
and werkzeug's `DispatcherMiddleware`, new `flask` extra).
|
|
152
|
+
- The SPA now uses relative asset and API URLs, so it works under any mount
|
|
153
|
+
prefix.
|
|
154
|
+
- Runnable `examples/fastapi_demo` and `examples/flask_demo`.
|
|
155
|
+
- New docs page `docs/integrations.md`.
|
|
156
|
+
|
|
157
|
+
**Packaging and docs**
|
|
158
|
+
|
|
159
|
+
- MkDocs Material documentation site under `docs/`.
|
|
160
|
+
- Root `README.md`, PyPI classifiers, keywords and project URLs; `uvicorn`
|
|
161
|
+
moved into a `standalone` extra since mounting the ASGI app into a server
|
|
162
|
+
you already run needs no server of its own.
|
|
163
|
+
- MIT license.
|
|
164
|
+
|
|
165
|
+
### Changed
|
|
166
|
+
|
|
167
|
+
- **`@track` now writes a `started` row before calling your task body**, not
|
|
168
|
+
only a terminal row afterwards. This is what makes an in-flight task
|
|
169
|
+
visible with no events-listener process running, and what gives
|
|
170
|
+
`report_progress()` a row to write to. **Cost: one extra INSERT/UPDATE and
|
|
171
|
+
commit per tracked run.** As with every other write in the decorator, a
|
|
172
|
+
failure is logged and dropped and can never change the task's outcome.
|
|
173
|
+
- `POST /api/schedules/{name}/occurrences/pause` now rejects
|
|
174
|
+
`action="reschedule"` with a `422`. It used to accept and store it, which
|
|
175
|
+
displayed the occurrence as paused while doing nothing — the decorator only
|
|
176
|
+
ever acted on `skip`/`cancel`. The column still permits the value; the
|
|
177
|
+
endpoint no longer does.
|
|
178
|
+
- The session cookie is now `Secure` by default (`cookie_secure=True`). Set
|
|
179
|
+
it to `False` only for local plain-HTTP development, where otherwise you
|
|
180
|
+
will log in successfully and then immediately appear logged out.
|
|
181
|
+
- `beat_schedule` entries are normalized through
|
|
182
|
+
`celery.schedules.maybe_schedule()`, so a bare number of seconds or a
|
|
183
|
+
`timedelta` works the same as an explicit `schedule()`/`crontab()`.
|
|
184
|
+
- `self.retry()` is now recorded as `retried` rather than `failed`. It raises
|
|
185
|
+
`celery.exceptions.Retry`, an ordinary `Exception` subclass, which used to
|
|
186
|
+
land in the decorator's failure branch and give a run Celery considers
|
|
187
|
+
RETRY a `failed` status, a "Retry in 30s: …" exception message and a finish
|
|
188
|
+
time it did not have.
|
|
189
|
+
- A retry attempt now clears what the previous attempt left on the shared row
|
|
190
|
+
(`exception`, `traceback`, `finished_at`, `runtime_seconds`, the four
|
|
191
|
+
`progress_*` columns). A task that failed once and then succeeded used to
|
|
192
|
+
render as `succeeded` with a stale traceback and a stale progress bar.
|
|
193
|
+
- `POST /api/tasks/{id}/retry` returns `404` for an unknown task id instead of
|
|
194
|
+
an unhandled `ValueError` (a `500`); `retry-bulk` does the same.
|
|
195
|
+
`control.TaskRunNotFound` is a `ValueError` subclass, so Python callers
|
|
196
|
+
already catching `ValueError` are unaffected.
|
|
197
|
+
|
|
198
|
+
### Fixed
|
|
199
|
+
|
|
200
|
+
- The events listener no longer downgrades a decorator-owned `skipped` status.
|
|
201
|
+
A skipped occurrence returns normally, so the worker emits an ordinary
|
|
202
|
+
`task-succeeded` for the same uuid — which used to flip the row back to
|
|
203
|
+
`succeeded`, making a paused occurrence look as if it had run.
|
|
204
|
+
- `EventBus.publish()` is thread-safe: subscribers are stored with the event
|
|
205
|
+
loop that owns their queue, and publishes are handed back to that loop via
|
|
206
|
+
`call_soon_threadsafe`.
|
|
207
|
+
- The decorator upserts `task_runs` instead of inserting, so it can't raise
|
|
208
|
+
`IntegrityError` when the events listener has already written a row for the
|
|
209
|
+
same uuid.
|
|
210
|
+
- Schedule overrides are matched by an `eta_tolerance_seconds` window rather
|
|
211
|
+
than exact timestamp equality, and each override is claimed by at most one
|
|
212
|
+
occurrence — so a paused occurrence keeps showing as paused, and can't show
|
|
213
|
+
as paused twice on a tightly-spaced schedule.
|
|
214
|
+
- Task timestamps are stamped back to UTC at the API boundary. SQLite drops
|
|
215
|
+
`tzinfo` on a `DateTime(timezone=True)` round-trip, so they used to reach
|
|
216
|
+
JSON unmarked and be parsed as *local* time by `new Date(...)`. The
|
|
217
|
+
`date_from`/`date_to` query parameters are normalized the same way on the
|
|
218
|
+
way in — an offset-carrying bound used to be compared by its wall-clock
|
|
219
|
+
fields, shifting the window by the caller's offset. `GET /api/audit`'s
|
|
220
|
+
`created_at` is stamped the same way.
|
|
221
|
+
- `GET /api/audit` clamps `limit` into `1..500`. SQLite reads `LIMIT -1` as
|
|
222
|
+
*no limit*, so `?limit=-1` returned the entire audit log in one response.
|
|
223
|
+
- The decorator no longer fails a task whose args it cannot JSON-encode. It
|
|
224
|
+
serializes args/kwargs *before* running the body, and a `datetime` kwarg —
|
|
225
|
+
supported by Celery's own serializer, rejected by stdlib `json.dumps` —
|
|
226
|
+
used to raise out of the wrapper and mark the task FAILURE without ever
|
|
227
|
+
running it. Unencodable leaves are now stored as their `repr`.
|
|
228
|
+
- The task list and the task detail page can no longer quote different
|
|
229
|
+
percentages for the same run: the rounding rule (a running task stops at
|
|
230
|
+
99% until it is genuinely complete) now lives in one shared derivation.
|
|
231
|
+
- A non-JSON SSE frame — a proxy's keep-alive comment, a truncated write — no
|
|
232
|
+
longer throws an uncaught error out of the event handler.
|
|
233
|
+
- The task detail page no longer repaints with a stale response when you
|
|
234
|
+
navigate from one live run to another while a fetch is in flight.
|
|
235
|
+
- The audit log and both schedule screens show the server's own error message
|
|
236
|
+
with a **Try again** button instead of a fixed sentence with nothing to
|
|
237
|
+
click.
|
|
238
|
+
- Retrying a run recorded only by the events listener no longer 500s. The
|
|
239
|
+
listener stores args/kwargs as a Python repr rather than JSON, so
|
|
240
|
+
`json.loads` failed for every undecorated task; the retry path now tries
|
|
241
|
+
JSON, then `ast.literal_eval`, and refuses rather than guessing if neither
|
|
242
|
+
works.
|
|
243
|
+
- `celery-manager events --celery-app module:app` now imports the app from the
|
|
244
|
+
current directory (console scripts don't put it on `sys.path`).
|
|
245
|
+
- SSE stream sends a `: keepalive` comment every 15s when idle so proxies don't
|
|
246
|
+
close it.
|
|
247
|
+
|
|
248
|
+
### Security
|
|
249
|
+
|
|
250
|
+
- **`create_app()` refuses to start with an empty or default
|
|
251
|
+
(`"change-me"`) `secret_key`**, raising `ValueError`. The default is
|
|
252
|
+
public, so a dashboard running on it accepted a session cookie anyone
|
|
253
|
+
could sign for any username. Workers and the events listener, which never
|
|
254
|
+
sign sessions, are unaffected. Generate a key with
|
|
255
|
+
`python -c "import secrets; print(secrets.token_urlsafe(32))"`.
|
|
256
|
+
- **`GET /api/stream` now requires a session**, like every other non-login
|
|
257
|
+
endpoint. It used to stream every task id and lifecycle event to anyone.
|
|
258
|
+
- **Login no longer reveals whether a username exists.** A missing user now
|
|
259
|
+
pays for a bcrypt check against a dummy hash, so both cases take the same
|
|
260
|
+
time (was ~0.2 s vs ~2 ms). A password over bcrypt's 72-byte limit is a
|
|
261
|
+
`401` for every username instead of a `500` for existing ones only.
|
|
262
|
+
- `create_user()` refuses an empty password (previously accepted) and one
|
|
263
|
+
over 72 bytes UTF-8-encoded with a clear `ValueError` — rather than
|
|
264
|
+
bcrypt's own error on bcrypt ≥ 5, or silent truncation to 72 bytes on
|
|
265
|
+
older bcrypt.
|
|
266
|
+
- A session cookie for a user that has since been deleted is rejected with
|
|
267
|
+
a `401`; it used to keep working until it expired.
|
|
268
|
+
- **Breaking for anyone on a dev SHA: the session cookie is renamed from
|
|
269
|
+
`session` to `cm_session`**, so it no longer collides with Flask's or
|
|
270
|
+
Starlette's own `session` cookie when celery-manager is mounted inside
|
|
271
|
+
another app. Its `Path` is now the app's mount point (`root_path`) rather
|
|
272
|
+
than always `/`. Existing sessions are not carried over — everyone signs in
|
|
273
|
+
once more, and the stale `session` cookie simply expires.
|
|
274
|
+
- Logout deletes the cookie with the same `Path`, `HttpOnly`, `SameSite=lax`
|
|
275
|
+
and `Secure` attributes it was set with.
|
|
276
|
+
- Cross-origin `POST`/`PUT`/`PATCH`/`DELETE` requests are refused with a
|
|
277
|
+
`403` when their `Origin` doesn't match `Host` (or `X-Forwarded-Host`).
|
|
278
|
+
Requests without `Origin` — curl, scripts — are unaffected. A proxy that
|
|
279
|
+
rewrites `Host` must forward the original as `X-Forwarded-Host`.
|
|
280
|
+
- Every response carries `X-Frame-Options: DENY` and
|
|
281
|
+
`Content-Security-Policy: frame-ancestors 'none'` against clickjacking.
|
|
282
|
+
- The `celery-manager events` CLI no longer accepts `--secret-key`, which it
|
|
283
|
+
never used. Drop it from any command line that passes it.
|
|
284
|
+
- New [Security model](docs/configuration.md#security-model) section in the
|
|
285
|
+
configuration docs: every account is a full administrator, there is no
|
|
286
|
+
login rate limiting, logout does not revoke a stolen cookie, and
|
|
287
|
+
`brand_logo_url` may point at an external host.
|
|
288
|
+
|
|
289
|
+
### Known limitations
|
|
290
|
+
|
|
291
|
+
- **SSE only carries web-process events.** `EventBus` is in-memory in the API
|
|
292
|
+
process, so with the documented deployment (events listener as a separate
|
|
293
|
+
process) `/api/stream` never delivers the listener's task events. The
|
|
294
|
+
dashboard's 5-second poll keeps it current. Don't build on `/api/stream` yet.
|
|
295
|
+
- **No schema migrations.** `init_db()` is `create_all` only; it creates
|
|
296
|
+
missing tables and never alters existing ones.
|
|
297
|
+
- **No role system.** Any authenticated user can perform any control action,
|
|
298
|
+
including dispatching any task name with any arguments.
|
|
299
|
+
- **No login rate limiting.** Rate-limit `POST /api/auth/login` at your
|
|
300
|
+
reverse proxy.
|
|
301
|
+
- **Sessions can't be revoked individually.** They are stateless signed
|
|
302
|
+
tokens valid for 7 days; rotating `secret_key` revokes all of them.
|
|
303
|
+
- `GET /api/settings` is unauthenticated by design (the login screen needs
|
|
304
|
+
the branding).
|
|
305
|
+
- `POST /api/tasks/retry-bulk` is not partial-failure aware: it stops at the
|
|
306
|
+
first unknown id and reports a `404` for the whole batch, after having
|
|
307
|
+
already dispatched the ids ahead of it.
|
|
308
|
+
- `task_runs.eta` is served by the detail endpoint but never written by
|
|
309
|
+
anything, so it is always `null`.
|
|
310
|
+
- Revoked runs have no `finished_at` (only `task-succeeded`/`task-failed` set it).
|
|
311
|
+
- Dispatching an unregistered task name records `task_name` as `"unknown"` when
|
|
312
|
+
the listener creates the row.
|
|
313
|
+
- The events listener needs `worker_send_task_events` (or `-E`) and
|
|
314
|
+
`task_send_sent_event` to be set; without them `worker`/`queue` are null. See
|
|
315
|
+
[Required Celery settings](docs/quickstart.md#required-celery-settings).
|
|
316
|
+
- **macOS prefork workers fail every task** (`ValueError: not enough values to
|
|
317
|
+
unpack`). Upstream Celery 5.6 / billiard 4.3 bug, not celery-manager. Start
|
|
318
|
+
the worker with `FORKED_BY_MULTIPROCESSING=1`, or use `--pool=threads` /
|
|
319
|
+
`--pool=solo` for local dev. See the [quickstart](docs/quickstart.md#required-celery-settings).
|
|
320
|
+
- Under Flask (a2wsgi) the SSE stream leaks a subscriber per disconnect, so
|
|
321
|
+
the Flask demo disables `/api/stream` and the dashboard falls back to
|
|
322
|
+
polling. Run the dashboard as its own uvicorn process for live push.
|
|
323
|
+
|
|
324
|
+
[0.1.0a2]: https://github.com/Pythondeveloper6/celery-manager/releases/tag/v0.1.0a2
|
|
325
|
+
[0.1.0a1]: https://github.com/Pythondeveloper6/celery-manager/releases/tag/v0.1.0a1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pythondeveloper6
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: celery-manager
|
|
3
|
+
Version: 0.1.0a2
|
|
4
|
+
Summary: A dashboard and control API for Celery background tasks.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Pythondeveloper6/celery-manager
|
|
6
|
+
Project-URL: Documentation, https://github.com/Pythondeveloper6/celery-manager/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/Pythondeveloper6/celery-manager
|
|
8
|
+
Project-URL: Issues, https://github.com/Pythondeveloper6/celery-manager/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/Pythondeveloper6/celery-manager/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: pythondeveloper6 <pythondeveloper6@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: celery,dashboard,monitoring,scheduler,task-queue
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Framework :: Celery
|
|
17
|
+
Classifier: Framework :: FastAPI
|
|
18
|
+
Classifier: Framework :: Flask
|
|
19
|
+
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Intended Audience :: System Administrators
|
|
21
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
29
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
30
|
+
Classifier: Topic :: System :: Monitoring
|
|
31
|
+
Requires-Python: >=3.10
|
|
32
|
+
Requires-Dist: bcrypt>=4.1
|
|
33
|
+
Requires-Dist: celery<6.0,>=5.3
|
|
34
|
+
Requires-Dist: fastapi<1.0,>=0.110
|
|
35
|
+
Requires-Dist: itsdangerous>=2.1
|
|
36
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
37
|
+
Requires-Dist: sqlalchemy<3.0,>=2.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: a2wsgi>=1.10; extra == 'dev'
|
|
40
|
+
Requires-Dist: flask>=3.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: ruff<0.18,>=0.17; extra == 'dev'
|
|
44
|
+
Requires-Dist: uvicorn>=0.29; extra == 'dev'
|
|
45
|
+
Provides-Extra: docs
|
|
46
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
47
|
+
Provides-Extra: flask
|
|
48
|
+
Requires-Dist: a2wsgi>=1.10; extra == 'flask'
|
|
49
|
+
Requires-Dist: flask>=3.0; extra == 'flask'
|
|
50
|
+
Provides-Extra: standalone
|
|
51
|
+
Requires-Dist: uvicorn>=0.29; extra == 'standalone'
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
<div align="center">
|
|
55
|
+
|
|
56
|
+
<h1>
|
|
57
|
+
<picture>
|
|
58
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Pythondeveloper6/celery-manager/main/docs/assets/logo-wordmark-dark.svg">
|
|
59
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Pythondeveloper6/celery-manager/main/docs/assets/logo-wordmark-light.svg">
|
|
60
|
+
<img alt="celery-manager" src="https://raw.githubusercontent.com/Pythondeveloper6/celery-manager/main/docs/assets/logo-wordmark-light.svg" height="56">
|
|
61
|
+
</picture>
|
|
62
|
+
</h1>
|
|
63
|
+
|
|
64
|
+
A dashboard and control API for Celery background tasks — for any
|
|
65
|
+
Django, Flask, or FastAPI project that already uses Celery.
|
|
66
|
+
|
|
67
|
+
[](https://github.com/Pythondeveloper6/celery-manager/actions/workflows/ci.yml)
|
|
68
|
+

|
|
69
|
+

|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
Point it at your existing Celery app and you get a web UI and a REST API to
|
|
75
|
+
see what your tasks are doing, act on them, and — the feature this project
|
|
76
|
+
exists for — **pause or cancel a single future occurrence of a periodic task**
|
|
77
|
+
without touching your beat schedule or restarting anything.
|
|
78
|
+
|
|
79
|
+
## What you get
|
|
80
|
+
|
|
81
|
+
- **Task visibility** — every task run (decorated or not) with status, args,
|
|
82
|
+
worker, queue, timings, exceptions, and full tracebacks.
|
|
83
|
+
- **Full run history** — browse past runs beyond the newest page, search by
|
|
84
|
+
task name, task ID, or args/kwargs content, and filter by status and date
|
|
85
|
+
range.
|
|
86
|
+
- **Live progress** — call `celery_manager.report_progress(current, total,
|
|
87
|
+
message)` inside a task body and watch the bar move, with elapsed time and
|
|
88
|
+
a projected finish while the task is still running.
|
|
89
|
+
- **Log capture** — `logging` output from inside a task body (and `print()`
|
|
90
|
+
too, in a real worker — [see why](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/decorator.md#what-log-capture-actually-captures)),
|
|
91
|
+
attached to that run and readable in the dashboard.
|
|
92
|
+
- **Control** — start, cancel/terminate, retry, and bulk retry, from the UI
|
|
93
|
+
or the API. Retries keep their lineage, so you can walk the chain.
|
|
94
|
+
- **Per-occurrence schedule control** — skip or cancel one upcoming run of a
|
|
95
|
+
periodic task, and see it stay paused.
|
|
96
|
+
- **Audit log** — who did what, when, for every control action.
|
|
97
|
+
- **Light and dark themes** — an explicit per-user choice, not just whatever
|
|
98
|
+
the OS says.
|
|
99
|
+
- **Brandable** — set the product name, accent colour, and logo from a
|
|
100
|
+
settings screen; it applies for everyone on the deployment.
|
|
101
|
+
- **Built-in auth** — bcrypt-hashed users and signed session cookies.
|
|
102
|
+
- **No Node toolchain required** — the React dashboard ships prebuilt inside
|
|
103
|
+
the Python package.
|
|
104
|
+
|
|
105
|
+
## Install
|
|
106
|
+
|
|
107
|
+
celery-manager is an alpha, so pass `--pre` to pip:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install --pre celery-manager
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
With extras:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pip install --pre "celery-manager[standalone]" # adds uvicorn
|
|
117
|
+
pip install --pre "celery-manager[flask]" # adds Flask and a2wsgi
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Alternatively, install a tagged release straight from git:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pip install "git+https://github.com/Pythondeveloper6/celery-manager.git@v0.1.0a2"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
(Extras with git: `"celery-manager[standalone] @
|
|
127
|
+
git+https://github.com/Pythondeveloper6/celery-manager.git@v0.1.0a2"`.)
|
|
128
|
+
|
|
129
|
+
Optional extras:
|
|
130
|
+
|
|
131
|
+
- `standalone` — pulls in uvicorn, to run the dashboard on its own rather than
|
|
132
|
+
mounting it into an ASGI app you already serve.
|
|
133
|
+
- `flask` — pulls in Flask and `a2wsgi`, to mount the dashboard in a Flask
|
|
134
|
+
(WSGI) app; see [Integrating with your app](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/integrations.md#flask-wsgi).
|
|
135
|
+
|
|
136
|
+
## Wire it up
|
|
137
|
+
|
|
138
|
+
celery-manager runs in two places, and **both** need configuring — this is
|
|
139
|
+
the step most easily missed:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from celery_manager.config import CeleryManagerConfig
|
|
143
|
+
|
|
144
|
+
config = CeleryManagerConfig(
|
|
145
|
+
celery_app=your_celery_app,
|
|
146
|
+
db_url="sqlite:///celery_manager.db", # any SQLAlchemy URL
|
|
147
|
+
secret_key="a-real-secret-in-production",
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**1. The dashboard process** — build the ASGI app and serve or mount it:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from celery_manager.api.app import create_app
|
|
155
|
+
|
|
156
|
+
app, _ = create_app(config) # then: uvicorn your_module:app
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**2. The Celery worker process** — where `@track`-decorated tasks actually
|
|
160
|
+
run:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import celery_manager
|
|
164
|
+
|
|
165
|
+
celery_manager.setup(config) # at import time, in your tasks module
|
|
166
|
+
|
|
167
|
+
@app.task(bind=True)
|
|
168
|
+
@celery_manager.track(schedule_name="send-report-every-2-hours")
|
|
169
|
+
def send_report(self):
|
|
170
|
+
...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Then run the events listener alongside your worker and beat, so the dashboard
|
|
174
|
+
sees every task rather than only the decorated ones:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
celery-manager events --celery-app your_module:your_celery_app \
|
|
178
|
+
--db-url sqlite:///celery_manager.db
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The listener sees nothing unless workers emit events: set `worker_send_task_events = True`
|
|
182
|
+
and `task_send_sent_event = True` (or run the worker with `-E`). See
|
|
183
|
+
[Required Celery settings](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/quickstart.md#required-celery-settings).
|
|
184
|
+
|
|
185
|
+
**Two things that stop people on a first run**, both covered in the
|
|
186
|
+
[Quickstart](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/quickstart.md): there is no default account, so you have to
|
|
187
|
+
create one (`celery_manager.auth.users.create_user`); and on plain HTTP you
|
|
188
|
+
need `cookie_secure=False`, or you will log in successfully and then
|
|
189
|
+
immediately appear logged out.
|
|
190
|
+
|
|
191
|
+
## Documentation
|
|
192
|
+
|
|
193
|
+
Full documentation lives in [`docs/`](https://github.com/Pythondeveloper6/celery-manager/tree/main/docs/) (an MkDocs Material site — run
|
|
194
|
+
`mkdocs serve` after `pip install -e ".[docs]"`):
|
|
195
|
+
|
|
196
|
+
- [Quickstart](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/quickstart.md) — install through first sign-in.
|
|
197
|
+
- [The `@track` decorator](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/decorator.md) — wiring, skip/cancel, logs.
|
|
198
|
+
- [Live progress](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/progress.md) — reporting progress from inside a task.
|
|
199
|
+
- [REST API](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/rest-api.md) — every endpoint and payload.
|
|
200
|
+
- [Dashboard](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/dashboard.md) — the screens and what they do.
|
|
201
|
+
- [Configuration](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/configuration.md) — every config field, the schema
|
|
202
|
+
and upgrade story, and production notes.
|
|
203
|
+
- [Working on celery-manager](https://github.com/Pythondeveloper6/celery-manager/blob/main/docs/contributing.md) — running the tests,
|
|
204
|
+
building the docs, and rebuilding the committed dashboard bundle.
|
|
205
|
+
|
|
206
|
+
Changes between versions — including what breaks for development builds —
|
|
207
|
+
are in [`CHANGELOG.md`](https://github.com/Pythondeveloper6/celery-manager/blob/main/CHANGELOG.md).
|
|
208
|
+
|
|
209
|
+
A complete runnable Django example is in
|
|
210
|
+
[`examples/django_demo/`](https://github.com/Pythondeveloper6/celery-manager/tree/main/examples/django_demo/).
|
|
211
|
+
|
|
212
|
+
## Requirements
|
|
213
|
+
|
|
214
|
+
Python 3.10+, Celery 5.x. Storage defaults to SQLite with zero configuration
|
|
215
|
+
and swaps to Postgres/MySQL/anything SQLAlchemy supports via `db_url`.
|
|
216
|
+
|
|
217
|
+
## Status
|
|
218
|
+
|
|
219
|
+
This is the first alpha, **0.1.0a2**. It is feature-complete for the v1 scope,
|
|
220
|
+
but APIs may change before 0.1.0. See [`plan.md`](https://github.com/Pythondeveloper6/celery-manager/blob/main/plan.md) for the implementation history and the
|
|
221
|
+
backlog of known gaps and planned follow-ups.
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT — see [`LICENSE`](https://github.com/Pythondeveloper6/celery-manager/blob/main/LICENSE).
|