You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,7 @@ uv run pytest -m "integration and benchmark"
18
18
uv run pytest --benchmark-compare # compare vs main baseline (run main first)
19
19
uvx prek run --all-files
20
20
uv run manage.py threadmill worker # run the worker pool
21
-
uv run manage.py threadmill inspector # launch the textual TUI inspector
21
+
uv run manage.py threadmill inspector # launch the textual TUI inspector
22
22
```
23
23
24
24
CI additionally pins Django per matrix step: `uv run --with django~=6.1a1 pytest -m "not benchmark"`.
@@ -28,8 +28,8 @@ Run a single test by node ID, e.g. `uv run pytest tests/test_command.py::TestCom
28
28
## Setup
29
29
30
30
- Install pre-commit hooks before first commit: `uvx prek install` (not `pre-commit install`).
31
-
-`DJANGO_SETTINGS_MODULE=tests.testapp.settings` is already set in `.env` and in `pyproject.toml`. Pytest auto-loads it.
32
-
- CI's Linux job starts a Redis service and sets `REDIS_URL`; some integration tests may rely on it. Local runs of `-m integration` may need Redis if a backend test targets it.
31
+
-`DJANGO_SETTINGS_MODULE=tests.testapp.settings` is set in `.env` and `pyproject.toml`; pytest auto-loads it.
32
+
- CI's Linux job starts Redis and sets `REDIS_URL`; some integration tests rely on it. Local `-m integration`runs may need Redis.
-Integration point for queue authors: `threadmill/backends.py` (`AcknowledgeableTaskBackend`) — subclasses implement `acquire` (lock-without-remove) and `acknowledge` (remove + publish). Requires late-ack support from the underlying queue.
55
+
-Queue author integration point: `threadmill/backends/base.py` (`ThreadmillTaskBackend`) — subclasses implement `acquire` (lock-without-remove) and `acknowledge` (remove + publish); requires late-ack support from the underlying queue.
56
56
- Test app backend `tests/testapp/backends.py` (`GeneratingTaskBackend`) generates tasks in-process for benchmarks; reset between runs via `default_task_backend.reset()`.
57
57
58
58
## Pre-commit
59
59
60
-
`.pre-commit-config.yaml` runs ruff (check + format), django-upgrade, pyupgrade, mdformat (excludes `.github/agents/`), yamlfmt, and `no-commit-to-branch` (protects `main`). Hooks auto-fix; ruff is configured `--exit-non-zero-on-fix`, so commit any fixes before pushing.
60
+
`.pre-commit-config.yaml` runs ruff (check + format), django-upgrade, pyupgrade, mdformat (excludes `.github/agents/`), yamlfmt, and `no-commit-to-branch` (protects `main`). Hooks auto-fix; ruff uses `--exit-non-zero-on-fix`, so commit fixes before pushing.
61
61
62
62
## PR / release
63
63
64
-
CI runs on `main` pushes and PRs. Releases are published to PyPI via `.github/workflows/release.yml` on GitHub release. Commits to `main` are blocked by `no-commit-to-branch`; work on a branch.
64
+
CI runs on `main` pushes and PRs. Releases publish to PyPI via `.github/workflows/release.yml` on GitHub release. `no-commit-to-branch` blocks commits to `main`; work on a branch.
Optionally, install the inspector dependency if you want the TUI:
64
+
Optionally, add the inspector extra for the TUI:
54
65
55
66
```console
56
67
uv add threadmill[inspector]
@@ -70,39 +81,33 @@ The workers are inspired by Gunicorn, and the CLI is very similar.
70
81
71
82
#### Utilization
72
83
73
-
Depending on your workload, you can tweak the number of processes and threads.
74
-
Processes allow for parallel compute (no GIL) while threads are great for low-memory concurrent IO.
84
+
Tune processes and threads to your workload. Processes bypass the GIL for parallel compute; threads suit low-memory concurrent IO.
75
85
76
86
```console
77
87
uv run manage.py threadmill worker --processes 4 --threads 2
78
88
```
79
89
80
90
#### Health
81
91
82
-
If your tasks leak memory, you can recycle (restart) the workers after a certain number of tasks have been processed:
92
+
Recycle workers after a number of tasks to reclaim leaked memory:
83
93
84
94
```console
85
95
uv run manage.py threadmill worker --max-tasks 1000 --max-tasks-jitter 100
86
96
```
87
97
88
-
This will restart the workers after 1000 tasks have been processed, with a random jitter of up to 100 tasks to avoid all workers restarting at the same time.
89
-
90
-
Should a worker crash or be killed, the pool will automatically restart it.
98
+
Jitter spreads restarts so workers do not recycle all at once. Crashed or killed workers are restarted automatically.
91
99
92
100
#### Shutdown
93
101
94
-
A graceful shutdown is possible with the `SIGTERM` or a keyboard interrupt.
95
-
All workers will finish the tasks they acquired and acknowledge them.
102
+
`SIGTERM` or a keyboard interrupt triggers a graceful shutdown: workers finish and acknowledge their in-flight tasks.
96
103
97
-
You can use `--exit-empty` to exit immediately after all tasks have been processed,
98
-
which might be useful for draining a one-off queue.
104
+
Use `--exit-empty` to exit once the queue is drained, useful for one-off queue processing.
@@ -121,17 +125,8 @@ The `RedisTaskBackend` accepts the following options under `OPTIONS` in your
121
125
|`broker_interval`|`timedelta(seconds=1)`| Interval between background broker maintenance passes. |
122
126
|`batch_size`|`100`| Max tasks to move or requeue per broker pass. |
123
127
124
-
A task that is started but never acknowledged (lease expired) is marked FAILED
125
-
with an `AcknowledgementTimeout` error. Set `lease_ttl` comfortably above your
126
-
worst-case task runtime.
127
-
128
-
All keys for one backend alias share a Redis Cluster hash tag (`{alias}`), so
129
-
every multi-key operation — including the cross-queue acquire — runs on a single
130
-
shard. Scale horizontally by running additional backend aliases, not by relying
131
-
on cross-slot operations.
128
+
A started task that is never acknowledged (lease expired) is marked FAILED with an `AcknowledgementTimeout` error. Set `lease_ttl` above your worst-case task runtime.
All keys for one backend alias share a Redis Cluster hash tag (`{alias}`), so every multi-key operation — including cross-queue acquire — runs on a single shard. Scale horizontally with additional backend aliases, not cross-slot operations.
0 commit comments