django-dbos 0.1.0__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_dbos-0.1.0/.github/workflows/ci.yml +60 -0
- django_dbos-0.1.0/.github/workflows/docs.yml +32 -0
- django_dbos-0.1.0/.github/workflows/release.yml +49 -0
- django_dbos-0.1.0/.gitignore +34 -0
- django_dbos-0.1.0/.pre-commit-config.yaml +31 -0
- django_dbos-0.1.0/AGENTS.md +137 -0
- django_dbos-0.1.0/CHANGELOG.md +11 -0
- django_dbos-0.1.0/CLAUDE.md +1 -0
- django_dbos-0.1.0/LICENSE +21 -0
- django_dbos-0.1.0/PKG-INFO +247 -0
- django_dbos-0.1.0/README.md +202 -0
- django_dbos-0.1.0/benchmarks/README.md +34 -0
- django_dbos-0.1.0/benchmarks/serializers.py +117 -0
- django_dbos-0.1.0/changelog_template.md.j2 +20 -0
- django_dbos-0.1.0/django_dbos/__init__.py +13 -0
- django_dbos-0.1.0/django_dbos/admin.py +257 -0
- django_dbos-0.1.0/django_dbos/admin_views.py +644 -0
- django_dbos-0.1.0/django_dbos/apps.py +28 -0
- django_dbos-0.1.0/django_dbos/backends.py +197 -0
- django_dbos-0.1.0/django_dbos/capacity.py +363 -0
- django_dbos-0.1.0/django_dbos/checks.py +260 -0
- django_dbos-0.1.0/django_dbos/client.py +91 -0
- django_dbos-0.1.0/django_dbos/context.py +357 -0
- django_dbos-0.1.0/django_dbos/dbos_setup.py +162 -0
- django_dbos-0.1.0/django_dbos/discovery.py +41 -0
- django_dbos-0.1.0/django_dbos/exceptions.py +83 -0
- django_dbos-0.1.0/django_dbos/heartbeat.py +217 -0
- django_dbos-0.1.0/django_dbos/logging.py +13 -0
- django_dbos-0.1.0/django_dbos/management/__init__.py +0 -0
- django_dbos-0.1.0/django_dbos/management/commands/__init__.py +0 -0
- django_dbos-0.1.0/django_dbos/management/commands/dbos.py +213 -0
- django_dbos-0.1.0/django_dbos/migrations/0001_initial.py +40 -0
- django_dbos-0.1.0/django_dbos/migrations/__init__.py +0 -0
- django_dbos-0.1.0/django_dbos/models.py +50 -0
- django_dbos-0.1.0/django_dbos/params.py +181 -0
- django_dbos-0.1.0/django_dbos/params_dataclass.py +55 -0
- django_dbos-0.1.0/django_dbos/pytest_plugin.py +288 -0
- django_dbos-0.1.0/django_dbos/results.py +199 -0
- django_dbos-0.1.0/django_dbos/retention.py +71 -0
- django_dbos-0.1.0/django_dbos/scheduling.py +219 -0
- django_dbos-0.1.0/django_dbos/sentry.py +163 -0
- django_dbos-0.1.0/django_dbos/serializers.py +134 -0
- django_dbos-0.1.0/django_dbos/settings.py +536 -0
- django_dbos-0.1.0/django_dbos/static/django_dbos/admin.css +134 -0
- django_dbos-0.1.0/django_dbos/system_db.py +161 -0
- django_dbos-0.1.0/django_dbos/system_engine.py +47 -0
- django_dbos-0.1.0/django_dbos/tasks.py +38 -0
- django_dbos-0.1.0/django_dbos/tasks_registry.py +246 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/base.html +10 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/delete_confirmation.html +15 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/error.html +10 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/schedule_list.html +50 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/workflow_detail.html +118 -0
- django_dbos-0.1.0/django_dbos/templates/admin/django_dbos/workflow_list.html +63 -0
- django_dbos-0.1.0/django_dbos/templatetags/__init__.py +0 -0
- django_dbos-0.1.0/django_dbos/templatetags/dbos_admin.py +41 -0
- django_dbos-0.1.0/django_dbos/test.py +35 -0
- django_dbos-0.1.0/django_dbos/workflow_names.py +40 -0
- django_dbos-0.1.0/docs/admin.md +101 -0
- django_dbos-0.1.0/docs/ai-agents.md +87 -0
- django_dbos-0.1.0/docs/assets/admin/schedules-dark.png +0 -0
- django_dbos-0.1.0/docs/assets/admin/schedules-light.png +0 -0
- django_dbos-0.1.0/docs/assets/admin/workflow-detail-dark.png +0 -0
- django_dbos-0.1.0/docs/assets/admin/workflow-detail-light.png +0 -0
- django_dbos-0.1.0/docs/assets/admin/workflows-dark.png +0 -0
- django_dbos-0.1.0/docs/assets/admin/workflows-light.png +0 -0
- django_dbos-0.1.0/docs/configuration.md +714 -0
- django_dbos-0.1.0/docs/cron.md +133 -0
- django_dbos-0.1.0/docs/deployment.md +299 -0
- django_dbos-0.1.0/docs/first-task.md +189 -0
- django_dbos-0.1.0/docs/index.md +146 -0
- django_dbos-0.1.0/docs/tasks.md +387 -0
- django_dbos-0.1.0/docs/testing.md +153 -0
- django_dbos-0.1.0/docs/troubleshooting.md +279 -0
- django_dbos-0.1.0/docs/worker-capacity.md +258 -0
- django_dbos-0.1.0/docs/workflows.md +365 -0
- django_dbos-0.1.0/examples/cron_report/.gitignore +3 -0
- django_dbos-0.1.0/examples/cron_report/README.md +67 -0
- django_dbos-0.1.0/examples/cron_report/config/__init__.py +0 -0
- django_dbos-0.1.0/examples/cron_report/config/settings.py +84 -0
- django_dbos-0.1.0/examples/cron_report/config/urls.py +6 -0
- django_dbos-0.1.0/examples/cron_report/manage.py +22 -0
- django_dbos-0.1.0/examples/cron_report/pyproject.toml +16 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/__init__.py +0 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/admin.py +5 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/management/__init__.py +0 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/management/commands/__init__.py +0 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/management/commands/seed_signups.py +18 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/migrations/0001_initial.py +20 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/migrations/__init__.py +0 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/models.py +9 -0
- django_dbos-0.1.0/examples/cron_report/reports_app/tasks.py +20 -0
- django_dbos-0.1.0/examples/cron_report/uv.lock +555 -0
- django_dbos-0.1.0/examples/ninja_api/.gitignore +3 -0
- django_dbos-0.1.0/examples/ninja_api/README.md +72 -0
- django_dbos-0.1.0/examples/ninja_api/config/__init__.py +0 -0
- django_dbos-0.1.0/examples/ninja_api/config/settings.py +86 -0
- django_dbos-0.1.0/examples/ninja_api/config/urls.py +8 -0
- django_dbos-0.1.0/examples/ninja_api/manage.py +22 -0
- django_dbos-0.1.0/examples/ninja_api/pyproject.toml +16 -0
- django_dbos-0.1.0/examples/ninja_api/tasks_app/__init__.py +0 -0
- django_dbos-0.1.0/examples/ninja_api/tasks_app/api.py +43 -0
- django_dbos-0.1.0/examples/ninja_api/tasks_app/tasks.py +15 -0
- django_dbos-0.1.0/examples/ninja_api/uv.lock +679 -0
- django_dbos-0.1.0/noxfile.py +43 -0
- django_dbos-0.1.0/pyproject.toml +168 -0
- django_dbos-0.1.0/scripts/admin_screenshots.py +236 -0
- django_dbos-0.1.0/skills/django-dbos/SKILL.md +463 -0
- django_dbos-0.1.0/tests/__init__.py +0 -0
- django_dbos-0.1.0/tests/conftest.py +32 -0
- django_dbos-0.1.0/tests/helpers.py +146 -0
- django_dbos-0.1.0/tests/settings.py +77 -0
- django_dbos-0.1.0/tests/tasks.py +204 -0
- django_dbos-0.1.0/tests/tasks_invalid_cron.py +11 -0
- django_dbos-0.1.0/tests/test_admin.py +699 -0
- django_dbos-0.1.0/tests/test_admin_format.py +40 -0
- django_dbos-0.1.0/tests/test_apps.py +26 -0
- django_dbos-0.1.0/tests/test_backends.py +170 -0
- django_dbos-0.1.0/tests/test_backends_client.py +173 -0
- django_dbos-0.1.0/tests/test_capacity.py +514 -0
- django_dbos-0.1.0/tests/test_checks.py +359 -0
- django_dbos-0.1.0/tests/test_client.py +154 -0
- django_dbos-0.1.0/tests/test_cockroachdb.py +83 -0
- django_dbos-0.1.0/tests/test_context.py +239 -0
- django_dbos-0.1.0/tests/test_cron.py +177 -0
- django_dbos-0.1.0/tests/test_dbos_setup.py +281 -0
- django_dbos-0.1.0/tests/test_discovery.py +62 -0
- django_dbos-0.1.0/tests/test_heartbeat.py +211 -0
- django_dbos-0.1.0/tests/test_integration.py +214 -0
- django_dbos-0.1.0/tests/test_integration_serializers.py +64 -0
- django_dbos-0.1.0/tests/test_migrate_command.py +103 -0
- django_dbos-0.1.0/tests/test_params.py +140 -0
- django_dbos-0.1.0/tests/test_public_helpers.py +15 -0
- django_dbos-0.1.0/tests/test_pytest_plugin.py +476 -0
- django_dbos-0.1.0/tests/test_registry.py +65 -0
- django_dbos-0.1.0/tests/test_results.py +201 -0
- django_dbos-0.1.0/tests/test_retention.py +82 -0
- django_dbos-0.1.0/tests/test_sentry.py +157 -0
- django_dbos-0.1.0/tests/test_serializers.py +186 -0
- django_dbos-0.1.0/tests/test_settings.py +514 -0
- django_dbos-0.1.0/tests/test_smoke.py +11 -0
- django_dbos-0.1.0/tests/test_system_db.py +262 -0
- django_dbos-0.1.0/tests/test_system_engine.py +40 -0
- django_dbos-0.1.0/tests/test_task_execution.py +175 -0
- django_dbos-0.1.0/tests/test_two_processes.py +54 -0
- django_dbos-0.1.0/tests/test_worker_command.py +102 -0
- django_dbos-0.1.0/tests/urls.py +8 -0
- django_dbos-0.1.0/tests/urls_two_sites.py +15 -0
- django_dbos-0.1.0/uv.lock +1916 -0
- django_dbos-0.1.0/zensical.toml +156 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
lint:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
timeout-minutes: 5
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
- uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5
|
|
21
|
+
- run: uv sync
|
|
22
|
+
- run: uv run ruff check .
|
|
23
|
+
- run: uv run ruff format --check .
|
|
24
|
+
- run: uv run pyrefly check --project-excludes 'examples/**'
|
|
25
|
+
|
|
26
|
+
tests:
|
|
27
|
+
runs-on: ${{ matrix.os }}
|
|
28
|
+
timeout-minutes: 10
|
|
29
|
+
permissions:
|
|
30
|
+
contents: read
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
35
|
+
python-version: ["3.12", "3.13", "3.14", "3.15"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
38
|
+
with:
|
|
39
|
+
persist-credentials: false
|
|
40
|
+
- uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5
|
|
41
|
+
- run: uv python install ${{ matrix.python-version }}
|
|
42
|
+
- run: uv run --python ${{ matrix.python-version }} pytest -m "not integration"
|
|
43
|
+
|
|
44
|
+
coverage:
|
|
45
|
+
# Whole suite against a real system database (PostgreSQL via
|
|
46
|
+
# testcontainers on the runner's Docker): unit tests plus admin pages,
|
|
47
|
+
# cron, capacity, dbos migrate and the two-process web/worker scenario.
|
|
48
|
+
# Subprocesses are measured too; fails under the fail_under floor.
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
timeout-minutes: 15
|
|
51
|
+
permissions:
|
|
52
|
+
contents: read
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
55
|
+
with:
|
|
56
|
+
persist-credentials: false
|
|
57
|
+
- uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5
|
|
58
|
+
- run: uv run coverage run -m pytest --dbos-system-db=postgres
|
|
59
|
+
- run: uv run coverage combine
|
|
60
|
+
- run: uv run coverage report --skip-covered --format=markdown >> "$GITHUB_STEP_SUMMARY"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Documentation
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
pages: write
|
|
8
|
+
id-token: write
|
|
9
|
+
jobs:
|
|
10
|
+
deploy:
|
|
11
|
+
# GitHub Pages is not available on private repositories (free plan): skip
|
|
12
|
+
# until the repository is public and Pages is enabled once (see AGENTS.md).
|
|
13
|
+
if: ${{ !github.event.repository.private }}
|
|
14
|
+
environment:
|
|
15
|
+
name: github-pages
|
|
16
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
20
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
24
|
+
with:
|
|
25
|
+
python-version: 3.x
|
|
26
|
+
- run: pip install zensical
|
|
27
|
+
- run: zensical build --clean
|
|
28
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
29
|
+
with:
|
|
30
|
+
path: site
|
|
31
|
+
- uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
32
|
+
id: deployment
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
timeout-minutes: 5
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: false
|
|
22
|
+
# Refuse to publish a tag that does not match the version in pyproject.toml.
|
|
23
|
+
- run: test "v$(uv version --short)" = "$GITHUB_REF_NAME"
|
|
24
|
+
- run: uv build
|
|
25
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist/
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
# Trusted publishing: PyPI accepts the OIDC token of this workflow
|
|
32
|
+
# (release.yml) running in the `pypi` environment, no API token needed.
|
|
33
|
+
needs: build
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
timeout-minutes: 5
|
|
36
|
+
environment:
|
|
37
|
+
name: pypi
|
|
38
|
+
url: https://pypi.org/project/django-dbos/
|
|
39
|
+
permissions:
|
|
40
|
+
id-token: write
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
- uses: astral-sh/setup-uv@ed21f2f24f8dd64503750218de024bcf64c7250a # v7.1.5
|
|
47
|
+
with:
|
|
48
|
+
enable-cache: false
|
|
49
|
+
- run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
|
|
12
|
+
# Tooling caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.nox/
|
|
16
|
+
.coverage
|
|
17
|
+
.coverage.*
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# Editors / OS
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
.DS_Store
|
|
24
|
+
|
|
25
|
+
# DBOS
|
|
26
|
+
dbos/
|
|
27
|
+
dbos.sqlite*
|
|
28
|
+
*.sqlite3
|
|
29
|
+
|
|
30
|
+
# ZCode local plans
|
|
31
|
+
.zcode/
|
|
32
|
+
|
|
33
|
+
# Docs build output
|
|
34
|
+
site/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
3
|
+
rev: v4.10.1
|
|
4
|
+
hooks:
|
|
5
|
+
- id: commitizen
|
|
6
|
+
- id: commitizen-branch
|
|
7
|
+
stages: [pre-push]
|
|
8
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
9
|
+
rev: v0.16.6
|
|
10
|
+
hooks:
|
|
11
|
+
- id: ruff
|
|
12
|
+
args: [--fix]
|
|
13
|
+
- id: ruff-format
|
|
14
|
+
- repo: https://github.com/osprey-oss/deptry.git
|
|
15
|
+
rev: 0c39226d761685125c5ff71ca81282d6751c9540 # 0.25.1
|
|
16
|
+
hooks:
|
|
17
|
+
- id: deptry
|
|
18
|
+
# The upstream hook hardcodes `deptry .` and would flag the test/dev
|
|
19
|
+
# tooling; scan only the shipped package.
|
|
20
|
+
entry: deptry django_dbos
|
|
21
|
+
pass_filenames: false
|
|
22
|
+
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
23
|
+
rev: v1.32.0
|
|
24
|
+
hooks:
|
|
25
|
+
- id: zizmor
|
|
26
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
27
|
+
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0
|
|
28
|
+
hooks:
|
|
29
|
+
- id: check-yaml
|
|
30
|
+
- id: end-of-file-fixer
|
|
31
|
+
- id: trailing-whitespace
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Reference for AI coding agents (and humans) working on this repository.
|
|
4
|
+
|
|
5
|
+
## Project
|
|
6
|
+
|
|
7
|
+
`django-dbos` is a DBOS-backed backend for Django's `django.tasks` framework:
|
|
8
|
+
durable background tasks, cron scheduling (`@cron`), optional Sentry cron
|
|
9
|
+
monitors, admin pages and a worker-capacity report. Published on PyPI.
|
|
10
|
+
|
|
11
|
+
## Layout
|
|
12
|
+
|
|
13
|
+
- Flat package layout: `django_dbos/` at the repo root (no `src/`), managed by **uv** and built with **hatchling**.
|
|
14
|
+
- `docs/` holds the user-facing documentation (Markdown only). The zensical
|
|
15
|
+
config lives at the root: `zensical.toml` (standard layout, do not move it
|
|
16
|
+
into `docs/` — the docs dir resolves relative to the config file).
|
|
17
|
+
- Tests in `tests/` are plain functions (not Django `TestCase` unless a DB is
|
|
18
|
+
needed); integration tests are marked `integration` and run against a real
|
|
19
|
+
system database (PostgreSQL via testcontainers, SQLite file fallback;
|
|
20
|
+
`test_cockroachdb.py` starts its own CockroachDB container).
|
|
21
|
+
- `examples/` holds standalone runnable projects (own `pyproject.toml`/`uv.lock`,
|
|
22
|
+
`django-dbos` pulled in as an editable path dependency) demonstrating the
|
|
23
|
+
package end to end; not part of the root `uv` project or its dependency
|
|
24
|
+
extras, so `uv run pyrefly check` needs `--project-excludes 'examples/**'`
|
|
25
|
+
(its imports are not installed in the root `.venv`) — see Commands below.
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
uv run pytest # unit tests
|
|
31
|
+
uv run pytest -m integration # integration tests (Docker recommended)
|
|
32
|
+
uv run coverage run -m pytest && uv run coverage combine && uv run coverage report # coverage, see note
|
|
33
|
+
uv run ruff check . && uv run ruff format --check .
|
|
34
|
+
uv run pyrefly check --project-excludes 'examples/**' # type check (examples/ are separate projects)
|
|
35
|
+
uv run deptry django_dbos # dependency hygiene (package only)
|
|
36
|
+
uv run --group doc zensical build # docs (runs from the repo root)
|
|
37
|
+
uv run --with playwright scripts/admin_screenshots.py # regenerate docs/assets/admin/*.png after admin UI changes
|
|
38
|
+
uv run benchmarks/serializers.py # serializer timings quoted in docs/configuration.md
|
|
39
|
+
uv run cz bump # release (commitizen)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Coverage
|
|
43
|
+
|
|
44
|
+
Measured with branch coverage over `django_dbos`, floor **98 %** in
|
|
45
|
+
`[tool.coverage.report]`. Always measure with `coverage run -m pytest`, **not**
|
|
46
|
+
`pytest --cov`: the pytest plugin is imported by pytest before pytest-cov
|
|
47
|
+
starts tracing, so module-level lines would be reported as uncovered.
|
|
48
|
+
Subprocesses (the plugin's pytester runs, the two-process worker) are measured
|
|
49
|
+
too (`parallel = true`, `patch = ["subprocess"]`): each process writes its own
|
|
50
|
+
`.coverage.*` file, so run `coverage combine` before `coverage report`. A
|
|
51
|
+
subprocess killed abruptly writes no data.
|
|
52
|
+
|
|
53
|
+
### Test environment
|
|
54
|
+
|
|
55
|
+
- `[tool.uv] exclude-newer = "7 days"` pins fresh package resolution.
|
|
56
|
+
- `DJANGO_SETTINGS_MODULE=tests.settings`; `filterwarnings = ["error"]` —
|
|
57
|
+
warnings fail tests.
|
|
58
|
+
- Docker available → Postgres testcontainers for integration tests; otherwise
|
|
59
|
+
SQLite file fallback.
|
|
60
|
+
|
|
61
|
+
## Publishing the docs
|
|
62
|
+
|
|
63
|
+
The Documentation workflow deploys `zensical build` to GitHub Pages. It is
|
|
64
|
+
skipped while the repository is private (Pages needs a paid plan there).
|
|
65
|
+
When the repository goes public, enable Pages **once** with the "GitHub
|
|
66
|
+
Actions" source — `gh api -X POST repos/lewoudar/django-dbos/pages -f build_type=workflow`
|
|
67
|
+
or Settings › Pages — then every push to `main` deploys.
|
|
68
|
+
|
|
69
|
+
## Conventions
|
|
70
|
+
|
|
71
|
+
- Commit messages follow **conventional commits** (commitizen,
|
|
72
|
+
`cz_conventional_commits`, tag format `v$version`); CHANGELOG generated by
|
|
73
|
+
commitizen through `changelog_template.md.j2` (config key
|
|
74
|
+
`[tool.commitizen] template = ...`; regenerate with `cz changelog`, use
|
|
75
|
+
`--incremental` to preserve manually edited sections).
|
|
76
|
+
- Logging through structlog under the `django_dbos` logger.
|
|
77
|
+
- CI workflows have their actions pinned by SHA (zizmor-checked); run
|
|
78
|
+
`uv run prek run --all-files` before committing (ruff, commitizen, deptry,
|
|
79
|
+
zizmor).
|
|
80
|
+
- The pytest plugin's runtime imports (pytest, testcontainers) are the
|
|
81
|
+
`django-dbos[test]` extra; deptry checks the package against the declared
|
|
82
|
+
dependencies and extras, so keep the extra in sync with the plugin.
|
|
83
|
+
- Python ≥ 3.12, Django ≥ 6.0.
|
|
84
|
+
|
|
85
|
+
## Process model (do not regress)
|
|
86
|
+
|
|
87
|
+
- Only `dbos worker` (and the `dbos_system` test fixture) may call
|
|
88
|
+
`dbos_setup.ensure_launched()`: `DBOS.launch()` starts queue/scheduler/
|
|
89
|
+
recovery threads, i.e. it turns the process into a worker. Everything else
|
|
90
|
+
(backend enqueue/get_result, admin views, `capacity.collect`) goes through
|
|
91
|
+
`client.get_client()` (a `DBOSClient`, system database only).
|
|
92
|
+
- The worker registers every known task (`tasks.known_tasks()`, filled by
|
|
93
|
+
`DBOSTask.__post_init__`) as a workflow *before* launch; clients enqueue by
|
|
94
|
+
workflow name and never hold workflow code.
|
|
95
|
+
- `manage.py migrate` migrates the system database through a `post_migrate`
|
|
96
|
+
receiver (`system_db.migrate_after_django_migrate`): a plain
|
|
97
|
+
`SystemDatabase` handle, never `ensure_launched()`. It must stay skipped for
|
|
98
|
+
`flush` (no `plan`), non-default aliases and test databases.
|
|
99
|
+
- Worker heartbeats live in the `WorkerHeartbeat` model (Django database),
|
|
100
|
+
not in the cache; the package ships a migration.
|
|
101
|
+
|
|
102
|
+
## Pitfalls learned the hard way
|
|
103
|
+
|
|
104
|
+
- `DBOSBackend.__init__` must not raise: Django builds the backend while
|
|
105
|
+
importing task modules and running its checks. A bad queue declaration is
|
|
106
|
+
stored, reported by `django_dbos.E001` and raised on enqueue. In tests,
|
|
107
|
+
override the backend's `OPTIONS` with
|
|
108
|
+
`tests.helpers.set_dbos_options(settings, {...})`.
|
|
109
|
+
- CockroachDB system database: DBOS forces `postgresql+psycopg` when given a
|
|
110
|
+
URL alone, and its SQL fails on CockroachDB under psycopg 3 (typed
|
|
111
|
+
parameters, `float * int`). `system_engine` builds a `cockroachdb+psycopg2`
|
|
112
|
+
engine for the worker and the client (`use_listen_notify=False`), and
|
|
113
|
+
`DBOS.migrate()` takes no engine, so `migrate` only creates the database:
|
|
114
|
+
the worker applies DBOS' migrations on launch (`django_dbos.E005`).
|
|
115
|
+
- **Never patch `django.conf.settings` attributes directly** (lazy object +
|
|
116
|
+
pytest-django `settings` fixture teardown = state leaks between tests).
|
|
117
|
+
Patch the module's own `settings` reference instead (see
|
|
118
|
+
`test_no_usable_django_database_raises` in `tests/test_settings.py`) or
|
|
119
|
+
override via the `settings` fixture for plain settings.
|
|
120
|
+
Overriding `DATABASES` through the fixture also raises a `UserWarning`
|
|
121
|
+
(fatal with `filterwarnings = ["error"]`).
|
|
122
|
+
- No private SDK import (`dbos._*`): workflow functions are kept in
|
|
123
|
+
`tasks_registry._workflows`, errors come from the public `dbos.error`
|
|
124
|
+
alias (`from dbos import error as dbos_error` — `from dbos.error import`
|
|
125
|
+
fails, it is an attribute, not a module), capacity lists active workflows
|
|
126
|
+
through `DBOSClient.list_workflows`. `DBOS.get_schedule` returns a
|
|
127
|
+
**dict**; the synchronous `retrieve_workflow()` refuses to run inside a
|
|
128
|
+
running event loop — use the `*_async` variants in async paths.
|
|
129
|
+
- `django.tasks` validates task construction (module-level function, declared
|
|
130
|
+
queue) at decoration time: build "rogue" tasks inside tests with
|
|
131
|
+
`dataclasses.replace` after overriding `TASKS`, not at module import.
|
|
132
|
+
- Admin URLs must be **prepended** to the admin's URL list (`dbos_urls + urls`)
|
|
133
|
+
or the admin's generic patterns swallow them; URL names are bare (`django_dbos_workflow_changelist`), the `admin:`
|
|
134
|
+
namespace is added by the
|
|
135
|
+
inclusion.
|
|
136
|
+
- DBOS/structlog log on stdout: in tests, capture a command's output with
|
|
137
|
+
`call_command(..., stdout=StringIO())` rather than `capsys`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## [0.1.0] - 2026-11-08
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- `DBOSBackend`, a backend for Django's `django.tasks` framework: every task runs as a durable DBOS workflow that survives crashes and restarts, with configurable queues (concurrency, rate limits) and pluggable serializers.
|
|
6
|
+
- Access to DBOS durable primitives (steps, sleep, events, messages) from inside a task through `get_dbos_context()`.
|
|
7
|
+
- `@cron` scheduling of tasks, with optional Sentry cron monitors.
|
|
8
|
+
- A `dbos` management command: `dbos worker` to run tasks, `dbos migrate` to set up the system database (also applied by `manage.py migrate`), and `dbos status` for a worker-capacity report with pluggable advice.
|
|
9
|
+
- Admin pages, restricted to superusers, to browse, cancel, resume and fork workflows and to manage schedules.
|
|
10
|
+
- PostgreSQL, SQLite and CockroachDB support for the DBOS system database.
|
|
11
|
+
- A pytest plugin (`django-dbos[test]` extra) with `dbos_inline` and `dbos_system` fixtures, to run tasks inline or against a real system database.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kevin Tewouda
|
|
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,247 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: django-dbos
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: DBOS-backed backend for Django's tasks framework: durable background tasks, cron scheduling and optional Sentry monitoring.
|
|
5
|
+
Project-URL: Homepage, https://github.com/lewoudar/django-dbos
|
|
6
|
+
Project-URL: Repository, https://github.com/lewoudar/django-dbos
|
|
7
|
+
Project-URL: Changelog, https://github.com/lewoudar/django-dbos/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: Kevin Tewouda <rollandkev@yahoo.fr>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Django :: 6.0
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: asgiref>=3.8
|
|
26
|
+
Requires-Dist: croniter>=6.0
|
|
27
|
+
Requires-Dist: dbos<4,>=3.0
|
|
28
|
+
Requires-Dist: django-click>=2.5.0
|
|
29
|
+
Requires-Dist: django<7,>=6.0
|
|
30
|
+
Requires-Dist: sqlalchemy<3,>=2.0
|
|
31
|
+
Requires-Dist: structlog>=25.1
|
|
32
|
+
Provides-Extra: cockroachdb
|
|
33
|
+
Requires-Dist: psycopg2-binary>=2.9; extra == 'cockroachdb'
|
|
34
|
+
Requires-Dist: sqlalchemy-cockroachdb>=2.0; extra == 'cockroachdb'
|
|
35
|
+
Provides-Extra: metrics
|
|
36
|
+
Requires-Dist: psutil>=7.0; extra == 'metrics'
|
|
37
|
+
Provides-Extra: msgspec
|
|
38
|
+
Requires-Dist: msgspec>=0.21; extra == 'msgspec'
|
|
39
|
+
Provides-Extra: sentry
|
|
40
|
+
Requires-Dist: sentry-sdk>=2.19; extra == 'sentry'
|
|
41
|
+
Provides-Extra: test
|
|
42
|
+
Requires-Dist: pytest>=8.4; extra == 'test'
|
|
43
|
+
Requires-Dist: testcontainers[postgres]>=4.13; extra == 'test'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# django-dbos
|
|
47
|
+
|
|
48
|
+
**⚠️ Experimental project. Do not use in production.**
|
|
49
|
+
|
|
50
|
+
A [DBOS](https://docs.dbos.dev/)-backed backend for Django's
|
|
51
|
+
[tasks framework](https://docs.djangoproject.com/en/stable/topics/tasks/):
|
|
52
|
+
background tasks that survive a worker crash, cron scheduling, optional
|
|
53
|
+
Sentry monitoring, an admin UI to inspect and operate on tasks, and a worker
|
|
54
|
+
capacity report to drive autoscaling.
|
|
55
|
+
|
|
56
|
+
## At a glance
|
|
57
|
+
|
|
58
|
+
If you know Django's tasks API, you already know django-dbos:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from django.tasks import task
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@task
|
|
65
|
+
def send_welcome_email(user_id: int) -> None: ...
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
result = send_welcome_email.enqueue(user_id) # durable by default
|
|
69
|
+
result.status # READY, RUNNING, SUCCESSFUL, FAILED — standard Django TaskResult
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Each enqueued task is recorded in a database before it runs. If the worker
|
|
73
|
+
executing it crashes, the task is not lost: it runs again once a worker is
|
|
74
|
+
back.
|
|
75
|
+
|
|
76
|
+
## Why DBOS
|
|
77
|
+
|
|
78
|
+
Say you send a newsletter to 10,000 users:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from django.tasks import task
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@task
|
|
85
|
+
def send_newsletter(campaign_id: int) -> None:
|
|
86
|
+
for user_id in User.objects.values_list('id', flat=True):
|
|
87
|
+
send_one_email(user_id, campaign_id)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
With most task backends, if the worker is killed at email #6,000 — a deploy,
|
|
91
|
+
an OOM, a spot instance reclaimed — the retry restarts the task from #1.
|
|
92
|
+
6,000 people get the same email twice.
|
|
93
|
+
|
|
94
|
+
With django-dbos, one option and one call per email turn the loop into a
|
|
95
|
+
durable, checkpointed workflow:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from django.tasks import task
|
|
99
|
+
from django_dbos import dbos_params, get_dbos_context
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dbos_params(durable_operations=True)
|
|
103
|
+
@task
|
|
104
|
+
def send_newsletter(campaign_id: int) -> None:
|
|
105
|
+
ctx = get_dbos_context()
|
|
106
|
+
for user_id in User.objects.values_list('id', flat=True):
|
|
107
|
+
ctx.run_step(send_one_email, user_id, campaign_id, name=f'email-{user_id}')
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Each `run_step` call is recorded in the system database as it completes.
|
|
111
|
+
Kill the worker at #6,000, restart it, and the task resumes from there: the
|
|
112
|
+
5,999 emails already sent are skipped, and only the one in flight at the
|
|
113
|
+
moment of the crash may go out again. No external state to reconcile, no
|
|
114
|
+
idempotency keys to invent yourself.
|
|
115
|
+
|
|
116
|
+
Cron schedules are just `@task`s with a firing time attached — same
|
|
117
|
+
durability, same retries, same admin page:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from django_dbos import cron
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@cron('0 3 * * *') # every day at 3am
|
|
124
|
+
@dbos_params(workflow_timeout=3600, step_retries_allowed=True)
|
|
125
|
+
@task
|
|
126
|
+
def nightly_report() -> None: ...
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Schedules are stored in the system database, so they keep firing across
|
|
130
|
+
restarts and deploys — and with the `sentry` extra installed, each firing
|
|
131
|
+
checks in with [Sentry Crons](https://docs.sentry.io/product/crons/)
|
|
132
|
+
automatically.
|
|
133
|
+
|
|
134
|
+
## What you get
|
|
135
|
+
|
|
136
|
+
- **Durable tasks** — every `.enqueue()` becomes a DBOS workflow: automatic
|
|
137
|
+
recovery after a crash, step retries with backoff, deferred execution
|
|
138
|
+
(`run_after`), deduplication, priorities and workflow timeouts, all through
|
|
139
|
+
Django's own `Task` / `TaskResult` API.
|
|
140
|
+
- **Durable workflows** *(opt-in)* — checkpointed steps, durable sleeps that
|
|
141
|
+
survive restarts, progress events, messages between workflows and child
|
|
142
|
+
workflows, from inside a task.
|
|
143
|
+
- **Cron scheduling** — `@cron('0 3 * * *')` on top of `@task`. Every worker
|
|
144
|
+
fires the schedules, each firing runs once, and no separate scheduler
|
|
145
|
+
process is needed.
|
|
146
|
+
- **Sentry cron monitoring** *(optional)* — scheduled tasks check in with
|
|
147
|
+
[Sentry Crons](https://docs.sentry.io/product/crons/) automatically, no
|
|
148
|
+
monitor to configure by hand.
|
|
149
|
+
- **Admin pages** — inspect every workflow (inputs, outputs, errors, step
|
|
150
|
+
history), and cancel, resume, fork or delete them; manage schedules; see
|
|
151
|
+
which workers are alive. Superuser-only.
|
|
152
|
+
- **Worker capacity report** — `dbos status` (or `capacity.collect()` from
|
|
153
|
+
Python) reports backlog, running count and per-worker load per queue, with
|
|
154
|
+
a scale up/down/OK verdict you can plug into an autoscaler.
|
|
155
|
+
- **Structured logging** — everything goes through
|
|
156
|
+
[structlog](https://www.structlog.org/) under the `django_dbos` logger.
|
|
157
|
+
- **A pytest plugin** — `dbos_inline` runs enqueued tasks synchronously for
|
|
158
|
+
fast unit tests; `dbos_system` launches a real DBOS system database
|
|
159
|
+
(SQLite or a Postgres testcontainer) when you need real semantics.
|
|
160
|
+
|
|
161
|
+
## Requirements
|
|
162
|
+
|
|
163
|
+
- Python 3.12+
|
|
164
|
+
- Django 6.0+
|
|
165
|
+
- A DBOS system database: PostgreSQL (recommended) or SQLite
|
|
166
|
+
|
|
167
|
+
## Installation
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
uv add django-dbos
|
|
171
|
+
# or
|
|
172
|
+
pip install django-dbos
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Poetry and PDM work too, see
|
|
176
|
+
[Installation](https://github.com/lewoudar/django-dbos/blob/main/docs/index.md#installation).
|
|
177
|
+
Add the `msgspec` extra (`uv add "django-dbos[msgspec]"` or
|
|
178
|
+
`pip install "django-dbos[msgspec]"`) for fast, safe serialization of task data; see
|
|
179
|
+
[Serialization](https://github.com/lewoudar/django-dbos/blob/main/docs/configuration.md#serialization).
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
INSTALLED_APPS = [
|
|
183
|
+
...,
|
|
184
|
+
'django_dbos',
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
TASKS = {
|
|
188
|
+
'default': {
|
|
189
|
+
'BACKEND': 'django_dbos.backends.DBOSBackend',
|
|
190
|
+
'QUEUES': ['default', 'emails'],
|
|
191
|
+
# other django-dbos settings go in 'OPTIONS', see the configuration docs
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
python manage.py migrate # Django's migrations, then the DBOS system database
|
|
198
|
+
python manage.py dbos worker # start executing tasks
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Put your tasks in a `tasks.py` module of an installed app: that is where the
|
|
202
|
+
worker looks for them. Your web processes only ever talk to the system
|
|
203
|
+
database — they enqueue tasks, they never execute them.
|
|
204
|
+
|
|
205
|
+
New to background tasks? [Your first task](https://github.com/lewoudar/django-dbos/blob/main/docs/first-task.md) walks through
|
|
206
|
+
writing, running and checking one, step by step.
|
|
207
|
+
|
|
208
|
+
## Using an AI coding agent
|
|
209
|
+
|
|
210
|
+
django-dbos ships an [agent skill](https://github.com/lewoudar/django-dbos/tree/main/skills/django-dbos)
|
|
211
|
+
that teaches AI coding agents (Claude Code, Codex, Cursor, OpenCode, Pi...)
|
|
212
|
+
how to write tasks, workflows and cron schedules with it. Install it with the
|
|
213
|
+
[`skills`](https://github.com/vercel-labs/skills) CLI:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
npx skills add lewoudar/django-dbos --skill django-dbos
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
[AI agents](https://github.com/lewoudar/django-dbos/blob/main/docs/ai-agents.md) has the command for each agent
|
|
220
|
+
and how to install the skill by hand.
|
|
221
|
+
|
|
222
|
+
## Examples
|
|
223
|
+
|
|
224
|
+
Two runnable projects in [`examples/`](https://github.com/lewoudar/django-dbos/tree/main/examples/), each a standalone `uv`
|
|
225
|
+
project you can `uv sync` and run on its own:
|
|
226
|
+
|
|
227
|
+
- [`ninja_api`](https://github.com/lewoudar/django-dbos/tree/main/examples/ninja_api) — a [Django Ninja](https://django-ninja.dev/)
|
|
228
|
+
API that enqueues a task and polls its status until it's done.
|
|
229
|
+
- [`cron_report`](https://github.com/lewoudar/django-dbos/tree/main/examples/cron_report) — a `@cron` task that fires on its
|
|
230
|
+
own once a worker is running, no external scheduler needed.
|
|
231
|
+
|
|
232
|
+
## Documentation
|
|
233
|
+
|
|
234
|
+
The full documentation lives in [`docs/`](https://github.com/lewoudar/django-dbos/tree/main/docs/) (a hosted version is coming
|
|
235
|
+
once the repository goes public). Good places to start:
|
|
236
|
+
|
|
237
|
+
- [Your first task](https://github.com/lewoudar/django-dbos/blob/main/docs/first-task.md) — a hands-on walkthrough.
|
|
238
|
+
- [Tasks](https://github.com/lewoudar/django-dbos/blob/main/docs/tasks.md) and [Workflows](https://github.com/lewoudar/django-dbos/blob/main/docs/workflows.md) — options,
|
|
239
|
+
retries, durable primitives.
|
|
240
|
+
- [Cron scheduling](https://github.com/lewoudar/django-dbos/blob/main/docs/cron.md) — schedules and Sentry monitors.
|
|
241
|
+
- [Deployment](https://github.com/lewoudar/django-dbos/blob/main/docs/deployment.md) — what to settle before production.
|
|
242
|
+
- [Troubleshooting](https://github.com/lewoudar/django-dbos/blob/main/docs/troubleshooting.md) — the errors you are most
|
|
243
|
+
likely to meet.
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT
|