smallage 0.2.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.
- smallage-0.2.0/.github/workflows/ci.yml +80 -0
- smallage-0.2.0/.github/workflows/publish.yml +74 -0
- smallage-0.2.0/.gitignore +212 -0
- smallage-0.2.0/.pre-commit-config.yaml +52 -0
- smallage-0.2.0/LICENSE +21 -0
- smallage-0.2.0/Makefile +35 -0
- smallage-0.2.0/PKG-INFO +162 -0
- smallage-0.2.0/README.md +134 -0
- smallage-0.2.0/docs/api.md +15 -0
- smallage-0.2.0/docs/assets/logo.png +0 -0
- smallage-0.2.0/docs/broker.md +100 -0
- smallage-0.2.0/docs/design.md +262 -0
- smallage-0.2.0/docs/index.md +95 -0
- smallage-0.2.0/docs/operations.md +204 -0
- smallage-0.2.0/docs/priorities.md +65 -0
- smallage-0.2.0/docs/results.md +87 -0
- smallage-0.2.0/docs/retries.md +93 -0
- smallage-0.2.0/docs/scheduling.md +90 -0
- smallage-0.2.0/docs/tasks.md +176 -0
- smallage-0.2.0/docs/testing.md +107 -0
- smallage-0.2.0/examples/README.md +50 -0
- smallage-0.2.0/examples/__init__.py +1 -0
- smallage-0.2.0/examples/basic_app.py +71 -0
- smallage-0.2.0/examples/broker_mode.py +54 -0
- smallage-0.2.0/examples/broker_only.py +53 -0
- smallage-0.2.0/examples/core_without_litestar.py +74 -0
- smallage-0.2.0/examples/cron_jobs.py +67 -0
- smallage-0.2.0/examples/deduplication.py +72 -0
- smallage-0.2.0/examples/deferred_publication.py +67 -0
- smallage-0.2.0/examples/delayed_jobs.py +76 -0
- smallage-0.2.0/examples/health_endpoint.py +66 -0
- smallage-0.2.0/examples/large_payloads.py +63 -0
- smallage-0.2.0/examples/priorities.py +66 -0
- smallage-0.2.0/examples/results.py +70 -0
- smallage-0.2.0/examples/retries_and_dlq.py +122 -0
- smallage-0.2.0/examples/sync_tasks_and_timeouts.py +75 -0
- smallage-0.2.0/examples/testing_your_app.py +118 -0
- smallage-0.2.0/examples/tracing.py +71 -0
- smallage-0.2.0/mkdocs.yml +64 -0
- smallage-0.2.0/pyproject.toml +187 -0
- smallage-0.2.0/src/smallage/__init__.py +90 -0
- smallage-0.2.0/src/smallage/core/__init__.py +87 -0
- smallage-0.2.0/src/smallage/core/clients.py +18 -0
- smallage-0.2.0/src/smallage/core/cron.py +87 -0
- smallage-0.2.0/src/smallage/core/deferred.py +81 -0
- smallage-0.2.0/src/smallage/core/envelope.py +138 -0
- smallage-0.2.0/src/smallage/core/errors.py +17 -0
- smallage-0.2.0/src/smallage/core/keys.py +81 -0
- smallage-0.2.0/src/smallage/core/payloads.py +66 -0
- smallage-0.2.0/src/smallage/core/protocols.py +116 -0
- smallage-0.2.0/src/smallage/core/results.py +76 -0
- smallage-0.2.0/src/smallage/core/retry.py +93 -0
- smallage-0.2.0/src/smallage/core/scheduler.py +138 -0
- smallage-0.2.0/src/smallage/core/scripts/__init__.py +60 -0
- smallage-0.2.0/src/smallage/core/scripts/ack.lua +31 -0
- smallage-0.2.0/src/smallage/core/scripts/promote.lua +43 -0
- smallage-0.2.0/src/smallage/core/scripts/reclaim.lua +30 -0
- smallage-0.2.0/src/smallage/core/scripts/release_leader.lua +11 -0
- smallage-0.2.0/src/smallage/core/scripts/renew_leader.lua +15 -0
- smallage-0.2.0/src/smallage/core/stats.py +43 -0
- smallage-0.2.0/src/smallage/core/testing.py +117 -0
- smallage-0.2.0/src/smallage/core/transport.py +372 -0
- smallage-0.2.0/src/smallage/core/worker.py +656 -0
- smallage-0.2.0/src/smallage/litestar/__init__.py +17 -0
- smallage-0.2.0/src/smallage/litestar/cli.py +103 -0
- smallage-0.2.0/src/smallage/litestar/config.py +85 -0
- smallage-0.2.0/src/smallage/litestar/di.py +134 -0
- smallage-0.2.0/src/smallage/litestar/health.py +40 -0
- smallage-0.2.0/src/smallage/litestar/plugin.py +187 -0
- smallage-0.2.0/src/smallage/litestar/registry.py +321 -0
- smallage-0.2.0/src/smallage/litestar/tracing.py +29 -0
- smallage-0.2.0/src/smallage/py.typed +0 -0
- smallage-0.2.0/tests/__init__.py +0 -0
- smallage-0.2.0/tests/conftest.py +30 -0
- smallage-0.2.0/tests/core/__init__.py +0 -0
- smallage-0.2.0/tests/core/integration/__init__.py +0 -0
- smallage-0.2.0/tests/core/integration/_worker_main.py +53 -0
- smallage-0.2.0/tests/core/integration/conftest.py +125 -0
- smallage-0.2.0/tests/core/integration/test_broker_topologies.py +131 -0
- smallage-0.2.0/tests/core/integration/test_connection_loss.py +73 -0
- smallage-0.2.0/tests/core/integration/test_results.py +99 -0
- smallage-0.2.0/tests/core/integration/test_scheduler.py +190 -0
- smallage-0.2.0/tests/core/integration/test_topologies.py +292 -0
- smallage-0.2.0/tests/core/integration/test_transport.py +309 -0
- smallage-0.2.0/tests/core/integration/test_worker.py +373 -0
- smallage-0.2.0/tests/core/integration/topologies.py +225 -0
- smallage-0.2.0/tests/core/unit/__init__.py +0 -0
- smallage-0.2.0/tests/core/unit/test_cron.py +93 -0
- smallage-0.2.0/tests/core/unit/test_deferred.py +81 -0
- smallage-0.2.0/tests/core/unit/test_envelope.py +91 -0
- smallage-0.2.0/tests/core/unit/test_keys.py +108 -0
- smallage-0.2.0/tests/core/unit/test_payloads.py +71 -0
- smallage-0.2.0/tests/core/unit/test_protocols.py +34 -0
- smallage-0.2.0/tests/core/unit/test_public_api.py +30 -0
- smallage-0.2.0/tests/core/unit/test_retry.py +94 -0
- smallage-0.2.0/tests/core/unit/test_scheduler_config.py +38 -0
- smallage-0.2.0/tests/core/unit/test_scripts.py +45 -0
- smallage-0.2.0/tests/core/unit/test_testing.py +46 -0
- smallage-0.2.0/tests/core/unit/test_transport_config.py +240 -0
- smallage-0.2.0/tests/core/unit/test_worker.py +1253 -0
- smallage-0.2.0/tests/litestar/__init__.py +0 -0
- smallage-0.2.0/tests/litestar/_worker_main.py +80 -0
- smallage-0.2.0/tests/litestar/conftest.py +24 -0
- smallage-0.2.0/tests/litestar/test_cli.py +186 -0
- smallage-0.2.0/tests/litestar/test_config.py +123 -0
- smallage-0.2.0/tests/litestar/test_di.py +154 -0
- smallage-0.2.0/tests/litestar/test_execution.py +73 -0
- smallage-0.2.0/tests/litestar/test_lifespan.py +97 -0
- smallage-0.2.0/tests/litestar/test_payload_offload.py +86 -0
- smallage-0.2.0/tests/litestar/test_plugin.py +398 -0
- smallage-0.2.0/tests/litestar/test_registry.py +283 -0
- smallage-0.2.0/tests/litestar/test_tracing.py +79 -0
- smallage-0.2.0/tests/test_docs.py +173 -0
- smallage-0.2.0/tests/test_examples.py +195 -0
- smallage-0.2.0/uv.lock +1471 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.13"
|
|
17
|
+
- uses: astral-sh/setup-uv@v4
|
|
18
|
+
- run: uv sync --frozen
|
|
19
|
+
- name: uv lock is current
|
|
20
|
+
run: uv lock --check
|
|
21
|
+
- name: Ruff check
|
|
22
|
+
run: uv run ruff check .
|
|
23
|
+
- name: Ruff format
|
|
24
|
+
run: uv run ruff format --check .
|
|
25
|
+
- name: Mypy
|
|
26
|
+
run: uv run mypy
|
|
27
|
+
- name: Import contracts
|
|
28
|
+
run: uv run lint-imports
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
# The library claims Redis 7 and up; each claimed major gets a run.
|
|
36
|
+
redis: ["redis:7-alpine", "redis:8-alpine"]
|
|
37
|
+
env:
|
|
38
|
+
REDIS_IMAGE: ${{ matrix.redis }}
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.13"
|
|
44
|
+
- uses: astral-sh/setup-uv@v4
|
|
45
|
+
- run: uv sync --frozen
|
|
46
|
+
- name: Pytest
|
|
47
|
+
run: uv run pytest -m "unit or integration" --cov --cov-report=term-missing
|
|
48
|
+
|
|
49
|
+
build-docs:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
needs: [lint, test]
|
|
52
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
- uses: actions/setup-python@v5
|
|
56
|
+
with:
|
|
57
|
+
python-version: "3.13"
|
|
58
|
+
- uses: astral-sh/setup-uv@v4
|
|
59
|
+
- run: uv sync --frozen
|
|
60
|
+
- name: Build MkDocs
|
|
61
|
+
run: uv run mkdocs build --strict
|
|
62
|
+
- name: Upload Pages artifact
|
|
63
|
+
uses: actions/upload-pages-artifact@v3
|
|
64
|
+
with:
|
|
65
|
+
path: site
|
|
66
|
+
|
|
67
|
+
deploy-pages:
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
needs: build-docs
|
|
70
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
71
|
+
permissions:
|
|
72
|
+
pages: write
|
|
73
|
+
id-token: write
|
|
74
|
+
environment:
|
|
75
|
+
name: github-pages
|
|
76
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
77
|
+
steps:
|
|
78
|
+
- name: Deploy to GitHub Pages
|
|
79
|
+
id: deployment
|
|
80
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.13"
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v4
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync
|
|
24
|
+
|
|
25
|
+
- name: Ruff check
|
|
26
|
+
run: uv run ruff check .
|
|
27
|
+
|
|
28
|
+
- name: Ruff format
|
|
29
|
+
run: uv run ruff format --check .
|
|
30
|
+
|
|
31
|
+
- name: Mypy
|
|
32
|
+
run: uv run mypy src/
|
|
33
|
+
|
|
34
|
+
- name: Pytest
|
|
35
|
+
run: uv run pytest -m unit
|
|
36
|
+
|
|
37
|
+
build:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: test
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.13"
|
|
47
|
+
|
|
48
|
+
- name: Install uv
|
|
49
|
+
uses: astral-sh/setup-uv@v4
|
|
50
|
+
|
|
51
|
+
- name: Build package
|
|
52
|
+
run: uv build
|
|
53
|
+
|
|
54
|
+
- name: Upload distributions
|
|
55
|
+
uses: actions/upload-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
|
|
60
|
+
publish:
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
needs: build
|
|
63
|
+
permissions:
|
|
64
|
+
id-token: write
|
|
65
|
+
environment: pypi
|
|
66
|
+
steps:
|
|
67
|
+
- name: Download distributions
|
|
68
|
+
uses: actions/download-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
|
|
73
|
+
- name: Publish to PyPI
|
|
74
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
#poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
#pdm.lock
|
|
116
|
+
#pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
#pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# SageMath parsed files
|
|
135
|
+
*.sage.py
|
|
136
|
+
|
|
137
|
+
# Environments
|
|
138
|
+
.env
|
|
139
|
+
.envrc
|
|
140
|
+
.venv
|
|
141
|
+
env/
|
|
142
|
+
venv/
|
|
143
|
+
ENV/
|
|
144
|
+
env.bak/
|
|
145
|
+
venv.bak/
|
|
146
|
+
|
|
147
|
+
# Spyder project settings
|
|
148
|
+
.spyderproject
|
|
149
|
+
.spyproject
|
|
150
|
+
|
|
151
|
+
# Rope project settings
|
|
152
|
+
.ropeproject
|
|
153
|
+
|
|
154
|
+
# mkdocs documentation
|
|
155
|
+
/site
|
|
156
|
+
|
|
157
|
+
# mypy
|
|
158
|
+
.mypy_cache/
|
|
159
|
+
.dmypy.json
|
|
160
|
+
dmypy.json
|
|
161
|
+
|
|
162
|
+
# Pyre type checker
|
|
163
|
+
.pyre/
|
|
164
|
+
|
|
165
|
+
# pytype static type analyzer
|
|
166
|
+
.pytype/
|
|
167
|
+
|
|
168
|
+
# Cython debug symbols
|
|
169
|
+
cython_debug/
|
|
170
|
+
|
|
171
|
+
# PyCharm
|
|
172
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
173
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
174
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
175
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
176
|
+
#.idea/
|
|
177
|
+
|
|
178
|
+
# Abstra
|
|
179
|
+
# Abstra is an AI-powered process automation framework.
|
|
180
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
181
|
+
# Learn more at https://abstra.io/docs
|
|
182
|
+
.abstra/
|
|
183
|
+
|
|
184
|
+
# Visual Studio Code
|
|
185
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
186
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
188
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
189
|
+
# .vscode/
|
|
190
|
+
|
|
191
|
+
# Ruff stuff:
|
|
192
|
+
.ruff_cache/
|
|
193
|
+
|
|
194
|
+
# PyPI configuration file
|
|
195
|
+
.pypirc
|
|
196
|
+
|
|
197
|
+
# Cursor
|
|
198
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
199
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
200
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
201
|
+
.cursorignore
|
|
202
|
+
.cursorindexingignore
|
|
203
|
+
|
|
204
|
+
# Marimo
|
|
205
|
+
marimo/_static/
|
|
206
|
+
marimo/_lsp/
|
|
207
|
+
__marimo__/
|
|
208
|
+
|
|
209
|
+
# MacOS
|
|
210
|
+
|
|
211
|
+
.DS_Store
|
|
212
|
+
.python-version
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# See https://pre-commit.com for more information
|
|
2
|
+
repos:
|
|
3
|
+
- repo: local
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
name: ruff
|
|
7
|
+
entry: uv run ruff check
|
|
8
|
+
language: system
|
|
9
|
+
types: [python]
|
|
10
|
+
|
|
11
|
+
- id: ruff-format
|
|
12
|
+
name: ruff-format
|
|
13
|
+
entry: uv run ruff format
|
|
14
|
+
language: system
|
|
15
|
+
types: [python]
|
|
16
|
+
|
|
17
|
+
- repo: local
|
|
18
|
+
hooks:
|
|
19
|
+
- id: mypy
|
|
20
|
+
name: mypy
|
|
21
|
+
entry: uv run mypy
|
|
22
|
+
language: system
|
|
23
|
+
pass_filenames: false
|
|
24
|
+
|
|
25
|
+
- id: lint-imports
|
|
26
|
+
name: import-linter
|
|
27
|
+
entry: uv run lint-imports
|
|
28
|
+
language: system
|
|
29
|
+
pass_filenames: false
|
|
30
|
+
|
|
31
|
+
- id: uv-lock-check
|
|
32
|
+
name: uv lock --check
|
|
33
|
+
entry: uv lock --check
|
|
34
|
+
language: system
|
|
35
|
+
pass_filenames: false
|
|
36
|
+
|
|
37
|
+
- id: pytest
|
|
38
|
+
name: pytest (unit)
|
|
39
|
+
entry: uv run pytest -m unit
|
|
40
|
+
language: system
|
|
41
|
+
pass_filenames: false
|
|
42
|
+
|
|
43
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
44
|
+
rev: v5.0.0
|
|
45
|
+
hooks:
|
|
46
|
+
- id: trailing-whitespace
|
|
47
|
+
- id: end-of-file-fixer
|
|
48
|
+
- id: check-yaml
|
|
49
|
+
- id: check-toml
|
|
50
|
+
- id: mixed-line-ending
|
|
51
|
+
- id: check-added-large-files
|
|
52
|
+
args: ["--maxkb=1000"]
|
smallage-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maksim Smirnov
|
|
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.
|
smallage-0.2.0/Makefile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.DEFAULT_GOAL := check
|
|
2
|
+
|
|
3
|
+
install:
|
|
4
|
+
uv sync
|
|
5
|
+
uv run pre-commit install
|
|
6
|
+
|
|
7
|
+
lint:
|
|
8
|
+
uv run ruff check .
|
|
9
|
+
uv run ruff format --check .
|
|
10
|
+
|
|
11
|
+
format:
|
|
12
|
+
uv run ruff format .
|
|
13
|
+
uv run ruff check --fix .
|
|
14
|
+
|
|
15
|
+
typecheck:
|
|
16
|
+
uv run mypy
|
|
17
|
+
|
|
18
|
+
imports:
|
|
19
|
+
uv run lint-imports
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
uv run pytest -m unit
|
|
23
|
+
|
|
24
|
+
test-int:
|
|
25
|
+
uv run pytest -m integration
|
|
26
|
+
|
|
27
|
+
cov:
|
|
28
|
+
uv run pytest --cov --cov-report=term-missing
|
|
29
|
+
|
|
30
|
+
docs:
|
|
31
|
+
uv run mkdocs build --strict
|
|
32
|
+
|
|
33
|
+
check: lint typecheck imports test
|
|
34
|
+
|
|
35
|
+
.PHONY: install lint format typecheck imports test test-int cov docs check
|
smallage-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: smallage
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Background tasks, cron and a dead letter queue on Redis Streams, with a Litestar integration
|
|
5
|
+
Project-URL: Homepage, https://github.com/smirnoffmg/smallage
|
|
6
|
+
Project-URL: Documentation, https://smirnoffmg.dev/smallage/
|
|
7
|
+
Project-URL: Source, https://github.com/smirnoffmg/smallage
|
|
8
|
+
Project-URL: Issues, https://github.com/smirnoffmg/smallage/issues
|
|
9
|
+
Author: Maksim Smirnov
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: background-tasks,celery,cron,dead-letter-queue,dlq,faststream,litestar,redis,redis-streams,streams,task-queue
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Framework :: AnyIO
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.13
|
|
21
|
+
Requires-Dist: anyio>=4.2
|
|
22
|
+
Requires-Dist: cronsim>=2.7
|
|
23
|
+
Requires-Dist: litestar>=2.0
|
|
24
|
+
Requires-Dist: msgspec>=0.18
|
|
25
|
+
Requires-Dist: redis[hiredis]>=5.0
|
|
26
|
+
Requires-Dist: uvloop>=0.21
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="https://raw.githubusercontent.com/smirnoffmg/smallage/main/docs/assets/logo.png"
|
|
31
|
+
alt="smallage — wild celery (Apium graveolens)" width="180">
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
# smallage
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/smallage/)
|
|
37
|
+
[](https://pypi.org/project/smallage/)
|
|
38
|
+
[](https://pypi.org/project/smallage/)
|
|
39
|
+
[](https://github.com/smirnoffmg/smallage/actions/workflows/ci.yml)
|
|
40
|
+
[](https://mypy-lang.org/)
|
|
41
|
+
|
|
42
|
+
Background tasks, cron and a dead letter queue on Redis Streams — typed tasks,
|
|
43
|
+
retries with backoff, delayed jobs, and consumption of streams somebody else
|
|
44
|
+
writes. The core reaches for no web framework; the
|
|
45
|
+
[Litestar](https://litestar.dev/) layer adds real dependency injection and a CLI
|
|
46
|
+
through the native plugin protocol.
|
|
47
|
+
|
|
48
|
+
*Smallage is the old name for wild celery.*
|
|
49
|
+
|
|
50
|
+
📖 **[Documentation](https://smirnoffmg.dev/smallage/)**
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- Tasks are ordinary functions: arguments are serialised, dependencies injected
|
|
55
|
+
- Retries with backoff, a delivery ceiling, and a dead letter queue that keeps
|
|
56
|
+
the payload, the traceback and the attempt history
|
|
57
|
+
- Delayed jobs and cron with no scheduler process, correct across DST
|
|
58
|
+
- Priority queues with a bounded starvation window, and shards for fairness
|
|
59
|
+
- Broker mode: consume streams somebody else writes, in the same worker
|
|
60
|
+
- Optional results, a deduplication gate, and trace context carried into the task
|
|
61
|
+
- Health endpoint served identically by the web process and the worker
|
|
62
|
+
- Eager mode, `assert_enqueued` and a real-worker fixture for your own tests
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv add smallage
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Redis 7 or newer. Standalone, Sentinel and Cluster are all covered by the test
|
|
71
|
+
suite.
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from dataclasses import dataclass
|
|
77
|
+
from uuid import UUID, uuid4
|
|
78
|
+
|
|
79
|
+
from litestar import Litestar, post
|
|
80
|
+
from litestar.di import Provide
|
|
81
|
+
|
|
82
|
+
from smallage.litestar import QueueConfig, QueuePlugin, TaskRegistry
|
|
83
|
+
|
|
84
|
+
tasks = TaskRegistry()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class Settings:
|
|
89
|
+
index_name: str = "documents"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def settings() -> Settings:
|
|
93
|
+
return Settings()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@tasks.task
|
|
97
|
+
async def reindex(doc_id: UUID, settings: Settings) -> None:
|
|
98
|
+
"""`doc_id` is serialised; `settings` comes from the application."""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@post("/documents")
|
|
102
|
+
async def create() -> str:
|
|
103
|
+
await reindex.enqueue(doc_id=uuid4())
|
|
104
|
+
return "queued"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
app = Litestar(
|
|
108
|
+
route_handlers=[create],
|
|
109
|
+
dependencies={"settings": Provide(settings, sync_to_thread=False)},
|
|
110
|
+
plugins=[QueuePlugin(QueueConfig(registry=tasks, redis_url="redis://localhost"))],
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`doc_id` travels in the payload; `settings` is injected in the worker from the
|
|
115
|
+
application's own dependency graph, and a real one would be a database session
|
|
116
|
+
or a client. There is no context dictionary.
|
|
117
|
+
|
|
118
|
+
## Workers
|
|
119
|
+
|
|
120
|
+
A worker is the same application, started differently:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
litestar workers run --queue high --concurrency 20
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The lifecycle comes with it: a worker enters the application's lifespan, so
|
|
127
|
+
`on_startup` hooks and lifespan managers run there too and a dependency closing
|
|
128
|
+
over what they opened is usable in a task. `run_app_lifespan=False` declines
|
|
129
|
+
that, for a lifespan whose work belongs to a web process alone.
|
|
130
|
+
|
|
131
|
+
Anything that can be settled at startup is — a task registered twice, an
|
|
132
|
+
argument with no annotation, a dependency the application does not provide, a
|
|
133
|
+
cycle, a provider only a request could satisfy — rather than on the first job in
|
|
134
|
+
production.
|
|
135
|
+
|
|
136
|
+
## Delivery guarantee
|
|
137
|
+
|
|
138
|
+
**At-least-once.** A worker that completed its side effect and died before
|
|
139
|
+
`XACK` will be reclaimed and the work repeated. No amount of protocol work
|
|
140
|
+
removes that; only an idempotent handler does. A `dedup` key is provided for the
|
|
141
|
+
cases where that is not naturally true.
|
|
142
|
+
|
|
143
|
+
## Documentation
|
|
144
|
+
|
|
145
|
+
Tasks, scheduling, retries, priorities, broker mode, results, testing and
|
|
146
|
+
operations are covered in the
|
|
147
|
+
**[full documentation](https://smirnoffmg.dev/smallage/)**. The rules the
|
|
148
|
+
library is built to are in
|
|
149
|
+
**[Design and invariants](https://smirnoffmg.dev/smallage/design/)**.
|
|
150
|
+
Runnable [examples](examples/) are included.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
make install # dependencies and git hooks
|
|
156
|
+
make check # lint, types, import contracts, unit tests
|
|
157
|
+
make test-int # integration suite, needs Docker
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|