dr-queues 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.
- dr_queues-0.1.0/.gitignore +4 -0
- dr_queues-0.1.0/.python-version +1 -0
- dr_queues-0.1.0/AGENTS.md +39 -0
- dr_queues-0.1.0/CHANGELOG.md +21 -0
- dr_queues-0.1.0/CLAUDE.md +1 -0
- dr_queues-0.1.0/LICENSE +21 -0
- dr_queues-0.1.0/PKG-INFO +243 -0
- dr_queues-0.1.0/README.md +219 -0
- dr_queues-0.1.0/docker-compose.yml +11 -0
- dr_queues-0.1.0/nbs/hello_world.py +35 -0
- dr_queues-0.1.0/pyproject.toml +95 -0
- dr_queues-0.1.0/scripts/pre-check.sh +57 -0
- dr_queues-0.1.0/scripts/run_pipeline_demo.py +4 -0
- dr_queues-0.1.0/scripts/run_stage_workers.py +4 -0
- dr_queues-0.1.0/src/dr_queues/__init__.py +77 -0
- dr_queues-0.1.0/src/dr_queues/amqp/__init__.py +18 -0
- dr_queues-0.1.0/src/dr_queues/amqp/connection.py +194 -0
- dr_queues-0.1.0/src/dr_queues/amqp/queues.py +66 -0
- dr_queues-0.1.0/src/dr_queues/analysis/__init__.py +3 -0
- dr_queues-0.1.0/src/dr_queues/analysis/filter.py +19 -0
- dr_queues-0.1.0/src/dr_queues/cli/__init__.py +6 -0
- dr_queues-0.1.0/src/dr_queues/cli/commands.py +14 -0
- dr_queues-0.1.0/src/dr_queues/cli/demo.py +143 -0
- dr_queues-0.1.0/src/dr_queues/cli/stage_worker.py +132 -0
- dr_queues-0.1.0/src/dr_queues/demo_handlers.py +38 -0
- dr_queues-0.1.0/src/dr_queues/events/__init__.py +21 -0
- dr_queues-0.1.0/src/dr_queues/events/amqp.py +118 -0
- dr_queues-0.1.0/src/dr_queues/events/memory.py +45 -0
- dr_queues-0.1.0/src/dr_queues/events/mongo.py +63 -0
- dr_queues-0.1.0/src/dr_queues/events/schema.py +34 -0
- dr_queues-0.1.0/src/dr_queues/events/sink.py +14 -0
- dr_queues-0.1.0/src/dr_queues/manifest/__init__.py +29 -0
- dr_queues-0.1.0/src/dr_queues/manifest/manifest.py +110 -0
- dr_queues-0.1.0/src/dr_queues/pipeline/__init__.py +10 -0
- dr_queues-0.1.0/src/dr_queues/pipeline/job.py +47 -0
- dr_queues-0.1.0/src/dr_queues/pipeline/runner.py +207 -0
- dr_queues-0.1.0/src/dr_queues/pipeline/tap.py +102 -0
- dr_queues-0.1.0/src/dr_queues/pipeline/workers.py +155 -0
- dr_queues-0.1.0/src/dr_queues/py.typed +0 -0
- dr_queues-0.1.0/src/dr_queues/utils.py +10 -0
- dr_queues-0.1.0/src/dr_queues/workflow/__init__.py +16 -0
- dr_queues-0.1.0/src/dr_queues/workflow/definition.py +20 -0
- dr_queues-0.1.0/src/dr_queues/workflow/pipeline.py +61 -0
- dr_queues-0.1.0/src/dr_queues/workflow/registry.py +28 -0
- dr_queues-0.1.0/tests/.gitkeep +0 -0
- dr_queues-0.1.0/tests/conftest.py +99 -0
- dr_queues-0.1.0/tests/test_amqp_sink.py +25 -0
- dr_queues-0.1.0/tests/test_filter_events.py +31 -0
- dr_queues-0.1.0/tests/test_job_envelope.py +25 -0
- dr_queues-0.1.0/tests/test_manifest.py +50 -0
- dr_queues-0.1.0/tests/test_memory_sink.py +44 -0
- dr_queues-0.1.0/tests/test_mongo_sink.py +20 -0
- dr_queues-0.1.0/tests/test_pipeline.py +78 -0
- dr_queues-0.1.0/tests/test_pipeline_mongo.py +55 -0
- dr_queues-0.1.0/tests/test_registry.py +29 -0
- dr_queues-0.1.0/uv.lock +1730 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
## Verification
|
|
4
|
+
|
|
5
|
+
- **Cursor agents:** Do not run `scripts/pre-check.sh` unless the user
|
|
6
|
+
explicitly asks you to run checks or verification.
|
|
7
|
+
- **Other agents:** Run `scripts/pre-check.sh` after making code changes.
|
|
8
|
+
- Skip `scripts/pre-check.sh` after documentation-only or configuration-only
|
|
9
|
+
changes (non-Cursor agents).
|
|
10
|
+
- When running checks, treat every issue reported by `scripts/pre-check.sh` as
|
|
11
|
+
in scope to fix, even when the issue is outside the files you touched.
|
|
12
|
+
- Read failed check output from `.cache/pre-check/`.
|
|
13
|
+
|
|
14
|
+
## Tests
|
|
15
|
+
|
|
16
|
+
- Do not add tests unless the user explicitly asks for tests.
|
|
17
|
+
|
|
18
|
+
## Commits
|
|
19
|
+
|
|
20
|
+
- After completing a requested sequence of changes, commit the result unless
|
|
21
|
+
the user specifically asks not to commit at the end.
|
|
22
|
+
- Use a single-line commit message.
|
|
23
|
+
- If your own changes are easy to isolate, commit only your own changes.
|
|
24
|
+
- If your own changes are not cleanly extractable, commit all changes in the
|
|
25
|
+
files you touched.
|
|
26
|
+
- Before committing code changes, run `scripts/pre-check.sh` (non-Cursor agents,
|
|
27
|
+
or when the user explicitly asked you to run checks).
|
|
28
|
+
- Before committing documentation-only or configuration-only changes, do not run
|
|
29
|
+
`scripts/pre-check.sh`.
|
|
30
|
+
|
|
31
|
+
## Multi-Player Workflow
|
|
32
|
+
|
|
33
|
+
- Assume other agents and users may be operating in this repo at the same time.
|
|
34
|
+
- Never delete, revert, reset, or otherwise undo unexpected changes in the repo.
|
|
35
|
+
- Assume unexpected changes were made intentionally by the user or another
|
|
36
|
+
process.
|
|
37
|
+
- If unexpected changes appear suspect or make the requested work difficult,
|
|
38
|
+
ask how to proceed and describe the concern.
|
|
39
|
+
- Do not undo suspect changes while waiting for guidance.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-06-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- RabbitMQ multi-stage pipeline runtime (`WorkerPool`, `TerminalTap`, queue chaining)
|
|
13
|
+
- Slim `JobEnvelope` for job state on the wire
|
|
14
|
+
- `PipelineDefinition`, `HandlerRegistry`, and `Pipeline` workflow engine
|
|
15
|
+
- Append-only event sinks: `MongoEventSink` (default), `AmqpEventSink`, `MemoryEventSink`
|
|
16
|
+
- Run manifest for multi-process worker coordination
|
|
17
|
+
- `filter_run_events` analysis helper
|
|
18
|
+
- Console entry points: `dr-queues-demo`, `dr-queues-stage-worker`
|
|
19
|
+
- Reference dummy handlers in `dr_queues.demo_handlers`
|
|
20
|
+
|
|
21
|
+
[0.1.0]: https://github.com/danielle-rothermel/dr-queues/releases/tag/v0.1.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
dr_queues-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 danielle rothermel
|
|
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.
|
dr_queues-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dr-queues
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: RabbitMQ multi-stage pipeline runtime with append-only event sinks
|
|
5
|
+
Project-URL: Homepage, https://github.com/danielle-rothermel/dr-queues
|
|
6
|
+
Project-URL: Repository, https://github.com/danielle-rothermel/dr-queues
|
|
7
|
+
Project-URL: Issues, https://github.com/danielle-rothermel/dr-queues/issues
|
|
8
|
+
Author-email: Danielle Rothermel <danielle.rothermel@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: amqp,mongodb,pipeline,queue,rabbitmq,workflow
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
18
|
+
Requires-Python: >=3.13
|
|
19
|
+
Requires-Dist: pika>=1.4.1
|
|
20
|
+
Requires-Dist: pydantic>=2.13.4
|
|
21
|
+
Requires-Dist: pymongo>=4.16.0
|
|
22
|
+
Requires-Dist: typer>=0.26.7
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# dr-queues
|
|
26
|
+
|
|
27
|
+
RabbitMQ multi-stage pipeline runtime with append-only event sinks.
|
|
28
|
+
|
|
29
|
+
dr-queues is a domain-free library for running jobs through chained stage
|
|
30
|
+
queues, scaling worker pools per stage, and recording pipeline lifecycle
|
|
31
|
+
events to durable storage. It is the execution substrate for experiment
|
|
32
|
+
applications such as [dr-bottleneck](https://github.com/danielle-rothermel/dr-bottleneck).
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install dr-queues
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv add dr-queues
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
RabbitMQ and MongoDB are **not** bundled with the package — run them locally
|
|
47
|
+
(Docker Compose) or point `AMQP_URL` / `MONGODB_URL` at your infrastructure.
|
|
48
|
+
|
|
49
|
+
After install, try the demo CLI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
dr-queues-demo --repeats 2 --lanes 1
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## What dr-queues is
|
|
56
|
+
|
|
57
|
+
- AMQP staged pipeline: per-stage pending/completed queue pairs chained together
|
|
58
|
+
- Slim `JobEnvelope` for job state on the wire
|
|
59
|
+
- `WorkerPool` and `TerminalTap` with pluggable step handlers
|
|
60
|
+
- Append-only `EventSink` implementations (MongoDB happy path, AMQP optional)
|
|
61
|
+
- Run manifest for multi-process worker coordination
|
|
62
|
+
- Minimal workflow engine: ordered steps + `HandlerRegistry`
|
|
63
|
+
|
|
64
|
+
## What dr-queues is not
|
|
65
|
+
|
|
66
|
+
- LLM calls, prompts, or model profiles
|
|
67
|
+
- Dataset loading, HumanEval, or experiment metrics
|
|
68
|
+
- JSONL report assembly
|
|
69
|
+
- General domain EventBus / webhook dispatch (deferred to a future layer)
|
|
70
|
+
|
|
71
|
+
Workers append pipeline events **before** acking and forwarding jobs to the
|
|
72
|
+
next stage. That append-before-forward invariant matches an event-sourced
|
|
73
|
+
write-ahead log: durable telemetry precedes propagation.
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Python 3.13+ with [uv](https://docs.astral.sh/uv/)
|
|
78
|
+
- Docker Compose for local RabbitMQ and MongoDB
|
|
79
|
+
|
|
80
|
+
## Environment
|
|
81
|
+
|
|
82
|
+
| Variable | Default | Purpose |
|
|
83
|
+
|----------|---------|---------|
|
|
84
|
+
| `AMQP_URL` | `amqp://guest:guest@localhost:5672/` | RabbitMQ connection |
|
|
85
|
+
| `MONGODB_URL` | `mongodb://localhost:27017/dr_queues` | MongoDB event store |
|
|
86
|
+
|
|
87
|
+
## Local services
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
docker compose up -d
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- RabbitMQ management UI: http://localhost:15672 (guest/guest)
|
|
94
|
+
- MongoDB: `mongodb://localhost:27017/dr_queues`
|
|
95
|
+
|
|
96
|
+
## Quick start
|
|
97
|
+
|
|
98
|
+
From a git checkout:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv sync
|
|
102
|
+
docker compose up -d
|
|
103
|
+
uv run dr-queues-demo \
|
|
104
|
+
--repeats 5 \
|
|
105
|
+
--workers slow=4,transform=4,finalize=2
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Or use the repo script wrapper (same CLI):
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv run python scripts/run_pipeline_demo.py \
|
|
112
|
+
--repeats 5 \
|
|
113
|
+
--workers slow=4,transform=4,finalize=2
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The demo runs a 3-stage dummy pipeline (`sleep_ms` → `add_prefix` →
|
|
117
|
+
`record_artifact`) with MongoDB as the default event sink.
|
|
118
|
+
|
|
119
|
+
Options:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
dr-queues-demo --sink amqp --repeats 2
|
|
123
|
+
dr-queues-demo --sink both --lanes 1 --repeats 1
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Each run writes a manifest to `.runs/{run_id}/manifest.json`. The demo prints
|
|
127
|
+
`run_id=...` at the start — use that value when querying MongoDB (do not use the
|
|
128
|
+
literal placeholder `demo-...`).
|
|
129
|
+
|
|
130
|
+
On success you should see output like `events=70 terminals=10` for
|
|
131
|
+
`--repeats 5` with the default 2 lanes (10 jobs × 7 events per job).
|
|
132
|
+
|
|
133
|
+
### Inspect events in MongoDB
|
|
134
|
+
|
|
135
|
+
Events are stored in the `pipeline_events` collection. Replace
|
|
136
|
+
`YOUR_RUN_ID` with the `run_id` printed by the demo (e.g. `demo-56bd0ce5`).
|
|
137
|
+
|
|
138
|
+
Count events for one run:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
142
|
+
--eval 'db.pipeline_events.countDocuments({run_id: "YOUR_RUN_ID"})'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
List all run IDs that have events:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
149
|
+
--eval 'db.pipeline_events.distinct("run_id")'
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Count all events in the collection (across every run):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
156
|
+
--eval 'db.pipeline_events.countDocuments({})'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Preview a few events from a run:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
163
|
+
--eval 'db.pipeline_events.find({run_id: "YOUR_RUN_ID"}).limit(3).pretty()'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If counts are zero, check:
|
|
167
|
+
|
|
168
|
+
- You used the **actual** `run_id` from demo output, not the placeholder text.
|
|
169
|
+
- The demo used the default Mongo sink (`--sink mongo`). AMQP-only runs
|
|
170
|
+
(`--sink amqp`) do not write to MongoDB.
|
|
171
|
+
- MongoDB is running (`docker compose up -d`) and reachable at `MONGODB_URL`.
|
|
172
|
+
- You re-ran the demo after starting Mongo if the first attempt failed to connect.
|
|
173
|
+
|
|
174
|
+
## Package layout
|
|
175
|
+
|
|
176
|
+
| Module | Role |
|
|
177
|
+
|--------|------|
|
|
178
|
+
| `amqp/` | Connection helpers, stage queue pairs |
|
|
179
|
+
| `pipeline/` | `JobEnvelope`, `WorkerPool`, `TerminalTap`, runner |
|
|
180
|
+
| `events/` | `PipelineEvent`, `EventSink`, Mongo/AMQP/memory sinks |
|
|
181
|
+
| `manifest/` | Run manifest read/write, worker CLI helpers |
|
|
182
|
+
| `workflow/` | `PipelineDefinition`, `HandlerRegistry`, `Pipeline` |
|
|
183
|
+
| `analysis/` | `filter_run_events` |
|
|
184
|
+
|
|
185
|
+
## Public API
|
|
186
|
+
|
|
187
|
+
Import from `dr_queues`:
|
|
188
|
+
|
|
189
|
+
- **Setup / run:** `setup_run_queues`, `run_in_process`, `seed_jobs`, `seed_manifest_jobs`
|
|
190
|
+
- **Runtime:** `WorkerPool`, `TerminalTap`, `JobEnvelope`
|
|
191
|
+
- **Workflow:** `PipelineDefinition`, `HandlerRegistry`, `Pipeline`
|
|
192
|
+
- **Events:** `PipelineEvent`, `EventSink`, `MongoEventSink`, `AmqpEventSink`, `MemoryEventSink`
|
|
193
|
+
- **Analysis:** `filter_run_events`
|
|
194
|
+
|
|
195
|
+
## Detached stage workers
|
|
196
|
+
|
|
197
|
+
Resize or run a single stage in a separate process:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
dr-queues-stage-worker \
|
|
201
|
+
--run-id demo-abc123 \
|
|
202
|
+
--stage transform \
|
|
203
|
+
--workers 5 \
|
|
204
|
+
--replace
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Handlers must be registered in the worker process via `--handlers-module`
|
|
208
|
+
(default: `dr_queues.demo_handlers`).
|
|
209
|
+
|
|
210
|
+
## Future layers
|
|
211
|
+
|
|
212
|
+
A general EventBus, domain EventAdapter, and webhook/hook dispatch will likely
|
|
213
|
+
live in a separate package or in dr-bottleneck, built on top of dr-queues.
|
|
214
|
+
Pipeline lifecycle events may eventually map to versioned domain event types;
|
|
215
|
+
dr-queues stays focused on queue-based execution and pipeline telemetry.
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
uv sync
|
|
221
|
+
docker compose up -d
|
|
222
|
+
scripts/pre-check.sh # ruff, ty, pytest (14 tests)
|
|
223
|
+
uv run pytest -m integration # integration tests only; needs docker compose
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Full manual smoke test:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
dr-queues-demo \
|
|
230
|
+
--repeats 5 \
|
|
231
|
+
--workers slow=4,transform=4,finalize=2
|
|
232
|
+
|
|
233
|
+
# optional: exercise AMQP event sink instead of Mongo
|
|
234
|
+
dr-queues-demo --sink amqp --repeats 2
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Build a wheel locally before publishing:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
uv build
|
|
241
|
+
tar -tzf dist/dr_queues-*.tar.gz | head
|
|
242
|
+
unzip -l dist/dr_queues-*.whl
|
|
243
|
+
```
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# dr-queues
|
|
2
|
+
|
|
3
|
+
RabbitMQ multi-stage pipeline runtime with append-only event sinks.
|
|
4
|
+
|
|
5
|
+
dr-queues is a domain-free library for running jobs through chained stage
|
|
6
|
+
queues, scaling worker pools per stage, and recording pipeline lifecycle
|
|
7
|
+
events to durable storage. It is the execution substrate for experiment
|
|
8
|
+
applications such as [dr-bottleneck](https://github.com/danielle-rothermel/dr-bottleneck).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install dr-queues
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv add dr-queues
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
RabbitMQ and MongoDB are **not** bundled with the package — run them locally
|
|
23
|
+
(Docker Compose) or point `AMQP_URL` / `MONGODB_URL` at your infrastructure.
|
|
24
|
+
|
|
25
|
+
After install, try the demo CLI:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
dr-queues-demo --repeats 2 --lanes 1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What dr-queues is
|
|
32
|
+
|
|
33
|
+
- AMQP staged pipeline: per-stage pending/completed queue pairs chained together
|
|
34
|
+
- Slim `JobEnvelope` for job state on the wire
|
|
35
|
+
- `WorkerPool` and `TerminalTap` with pluggable step handlers
|
|
36
|
+
- Append-only `EventSink` implementations (MongoDB happy path, AMQP optional)
|
|
37
|
+
- Run manifest for multi-process worker coordination
|
|
38
|
+
- Minimal workflow engine: ordered steps + `HandlerRegistry`
|
|
39
|
+
|
|
40
|
+
## What dr-queues is not
|
|
41
|
+
|
|
42
|
+
- LLM calls, prompts, or model profiles
|
|
43
|
+
- Dataset loading, HumanEval, or experiment metrics
|
|
44
|
+
- JSONL report assembly
|
|
45
|
+
- General domain EventBus / webhook dispatch (deferred to a future layer)
|
|
46
|
+
|
|
47
|
+
Workers append pipeline events **before** acking and forwarding jobs to the
|
|
48
|
+
next stage. That append-before-forward invariant matches an event-sourced
|
|
49
|
+
write-ahead log: durable telemetry precedes propagation.
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.13+ with [uv](https://docs.astral.sh/uv/)
|
|
54
|
+
- Docker Compose for local RabbitMQ and MongoDB
|
|
55
|
+
|
|
56
|
+
## Environment
|
|
57
|
+
|
|
58
|
+
| Variable | Default | Purpose |
|
|
59
|
+
|----------|---------|---------|
|
|
60
|
+
| `AMQP_URL` | `amqp://guest:guest@localhost:5672/` | RabbitMQ connection |
|
|
61
|
+
| `MONGODB_URL` | `mongodb://localhost:27017/dr_queues` | MongoDB event store |
|
|
62
|
+
|
|
63
|
+
## Local services
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
docker compose up -d
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- RabbitMQ management UI: http://localhost:15672 (guest/guest)
|
|
70
|
+
- MongoDB: `mongodb://localhost:27017/dr_queues`
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
From a git checkout:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv sync
|
|
78
|
+
docker compose up -d
|
|
79
|
+
uv run dr-queues-demo \
|
|
80
|
+
--repeats 5 \
|
|
81
|
+
--workers slow=4,transform=4,finalize=2
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or use the repo script wrapper (same CLI):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv run python scripts/run_pipeline_demo.py \
|
|
88
|
+
--repeats 5 \
|
|
89
|
+
--workers slow=4,transform=4,finalize=2
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The demo runs a 3-stage dummy pipeline (`sleep_ms` → `add_prefix` →
|
|
93
|
+
`record_artifact`) with MongoDB as the default event sink.
|
|
94
|
+
|
|
95
|
+
Options:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
dr-queues-demo --sink amqp --repeats 2
|
|
99
|
+
dr-queues-demo --sink both --lanes 1 --repeats 1
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Each run writes a manifest to `.runs/{run_id}/manifest.json`. The demo prints
|
|
103
|
+
`run_id=...` at the start — use that value when querying MongoDB (do not use the
|
|
104
|
+
literal placeholder `demo-...`).
|
|
105
|
+
|
|
106
|
+
On success you should see output like `events=70 terminals=10` for
|
|
107
|
+
`--repeats 5` with the default 2 lanes (10 jobs × 7 events per job).
|
|
108
|
+
|
|
109
|
+
### Inspect events in MongoDB
|
|
110
|
+
|
|
111
|
+
Events are stored in the `pipeline_events` collection. Replace
|
|
112
|
+
`YOUR_RUN_ID` with the `run_id` printed by the demo (e.g. `demo-56bd0ce5`).
|
|
113
|
+
|
|
114
|
+
Count events for one run:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
118
|
+
--eval 'db.pipeline_events.countDocuments({run_id: "YOUR_RUN_ID"})'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
List all run IDs that have events:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
125
|
+
--eval 'db.pipeline_events.distinct("run_id")'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Count all events in the collection (across every run):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
132
|
+
--eval 'db.pipeline_events.countDocuments({})'
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Preview a few events from a run:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
mongosh mongodb://localhost:27017/dr_queues \
|
|
139
|
+
--eval 'db.pipeline_events.find({run_id: "YOUR_RUN_ID"}).limit(3).pretty()'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
If counts are zero, check:
|
|
143
|
+
|
|
144
|
+
- You used the **actual** `run_id` from demo output, not the placeholder text.
|
|
145
|
+
- The demo used the default Mongo sink (`--sink mongo`). AMQP-only runs
|
|
146
|
+
(`--sink amqp`) do not write to MongoDB.
|
|
147
|
+
- MongoDB is running (`docker compose up -d`) and reachable at `MONGODB_URL`.
|
|
148
|
+
- You re-ran the demo after starting Mongo if the first attempt failed to connect.
|
|
149
|
+
|
|
150
|
+
## Package layout
|
|
151
|
+
|
|
152
|
+
| Module | Role |
|
|
153
|
+
|--------|------|
|
|
154
|
+
| `amqp/` | Connection helpers, stage queue pairs |
|
|
155
|
+
| `pipeline/` | `JobEnvelope`, `WorkerPool`, `TerminalTap`, runner |
|
|
156
|
+
| `events/` | `PipelineEvent`, `EventSink`, Mongo/AMQP/memory sinks |
|
|
157
|
+
| `manifest/` | Run manifest read/write, worker CLI helpers |
|
|
158
|
+
| `workflow/` | `PipelineDefinition`, `HandlerRegistry`, `Pipeline` |
|
|
159
|
+
| `analysis/` | `filter_run_events` |
|
|
160
|
+
|
|
161
|
+
## Public API
|
|
162
|
+
|
|
163
|
+
Import from `dr_queues`:
|
|
164
|
+
|
|
165
|
+
- **Setup / run:** `setup_run_queues`, `run_in_process`, `seed_jobs`, `seed_manifest_jobs`
|
|
166
|
+
- **Runtime:** `WorkerPool`, `TerminalTap`, `JobEnvelope`
|
|
167
|
+
- **Workflow:** `PipelineDefinition`, `HandlerRegistry`, `Pipeline`
|
|
168
|
+
- **Events:** `PipelineEvent`, `EventSink`, `MongoEventSink`, `AmqpEventSink`, `MemoryEventSink`
|
|
169
|
+
- **Analysis:** `filter_run_events`
|
|
170
|
+
|
|
171
|
+
## Detached stage workers
|
|
172
|
+
|
|
173
|
+
Resize or run a single stage in a separate process:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
dr-queues-stage-worker \
|
|
177
|
+
--run-id demo-abc123 \
|
|
178
|
+
--stage transform \
|
|
179
|
+
--workers 5 \
|
|
180
|
+
--replace
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Handlers must be registered in the worker process via `--handlers-module`
|
|
184
|
+
(default: `dr_queues.demo_handlers`).
|
|
185
|
+
|
|
186
|
+
## Future layers
|
|
187
|
+
|
|
188
|
+
A general EventBus, domain EventAdapter, and webhook/hook dispatch will likely
|
|
189
|
+
live in a separate package or in dr-bottleneck, built on top of dr-queues.
|
|
190
|
+
Pipeline lifecycle events may eventually map to versioned domain event types;
|
|
191
|
+
dr-queues stays focused on queue-based execution and pipeline telemetry.
|
|
192
|
+
|
|
193
|
+
## Development
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
uv sync
|
|
197
|
+
docker compose up -d
|
|
198
|
+
scripts/pre-check.sh # ruff, ty, pytest (14 tests)
|
|
199
|
+
uv run pytest -m integration # integration tests only; needs docker compose
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Full manual smoke test:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
dr-queues-demo \
|
|
206
|
+
--repeats 5 \
|
|
207
|
+
--workers slow=4,transform=4,finalize=2
|
|
208
|
+
|
|
209
|
+
# optional: exercise AMQP event sink instead of Mongo
|
|
210
|
+
dr-queues-demo --sink amqp --repeats 2
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Build a wheel locally before publishing:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
uv build
|
|
217
|
+
tar -tzf dist/dr_queues-*.tar.gz | head
|
|
218
|
+
unzip -l dist/dr_queues-*.whl
|
|
219
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import marimo
|
|
2
|
+
|
|
3
|
+
__generated_with = "0.23.9"
|
|
4
|
+
app = marimo.App(width="columns")
|
|
5
|
+
|
|
6
|
+
with app.setup:
|
|
7
|
+
import marimo as mo
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@app.cell
|
|
11
|
+
def _():
|
|
12
|
+
mo.md(r"""
|
|
13
|
+
## Load Data
|
|
14
|
+
""")
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.cell(column=1)
|
|
19
|
+
def _():
|
|
20
|
+
mo.md(r"""
|
|
21
|
+
## Do Exploration
|
|
22
|
+
""")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.cell(column=2, hide_code=True)
|
|
27
|
+
def _():
|
|
28
|
+
mo.md(r"""
|
|
29
|
+
(leave space)
|
|
30
|
+
""")
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
app.run()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dr-queues"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "RabbitMQ multi-stage pipeline runtime with append-only event sinks"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Danielle Rothermel", email = "danielle.rothermel@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.13"
|
|
12
|
+
keywords = ["rabbitmq", "pipeline", "workflow", "queue", "amqp", "mongodb"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: System :: Distributed Computing",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"pika>=1.4.1",
|
|
23
|
+
"pydantic>=2.13.4",
|
|
24
|
+
"pymongo>=4.16.0",
|
|
25
|
+
"typer>=0.26.7",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/danielle-rothermel/dr-queues"
|
|
30
|
+
Repository = "https://github.com/danielle-rothermel/dr-queues"
|
|
31
|
+
Issues = "https://github.com/danielle-rothermel/dr-queues/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
dr-queues-demo = "dr_queues.cli.demo:run"
|
|
35
|
+
dr-queues-stage-worker = "dr_queues.cli.stage_worker:run"
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["hatchling"]
|
|
39
|
+
build-backend = "hatchling.build"
|
|
40
|
+
|
|
41
|
+
[tool.hatch.build.targets.wheel]
|
|
42
|
+
packages = ["src/dr_queues"]
|
|
43
|
+
|
|
44
|
+
[dependency-groups]
|
|
45
|
+
dev = [
|
|
46
|
+
"marimo[recommended]>=0.23.10",
|
|
47
|
+
"pytest>=9.1.1",
|
|
48
|
+
"ruff>=0.15.18",
|
|
49
|
+
"ty>=0.0.51",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
markers = [
|
|
55
|
+
"integration: tests requiring RabbitMQ and/or MongoDB",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
include = ["scripts/**/*.py", "src/**/*.py", "tests/**/*.py"]
|
|
60
|
+
line-length = 79
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = [
|
|
64
|
+
"A",
|
|
65
|
+
"ARG",
|
|
66
|
+
"ASYNC",
|
|
67
|
+
"DTZ",
|
|
68
|
+
"FA",
|
|
69
|
+
"FLY",
|
|
70
|
+
"FURB",
|
|
71
|
+
"G",
|
|
72
|
+
"I",
|
|
73
|
+
"ICN",
|
|
74
|
+
"ISC",
|
|
75
|
+
"LOG",
|
|
76
|
+
"N",
|
|
77
|
+
"NPY",
|
|
78
|
+
"PD",
|
|
79
|
+
"PIE",
|
|
80
|
+
"PTH",
|
|
81
|
+
"PT",
|
|
82
|
+
"RET",
|
|
83
|
+
"RSE",
|
|
84
|
+
"RUF",
|
|
85
|
+
"SLOT",
|
|
86
|
+
"T10",
|
|
87
|
+
"TID",
|
|
88
|
+
"UP",
|
|
89
|
+
"W",
|
|
90
|
+
"YTT",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[tool.ty.src]
|
|
94
|
+
include = ["scripts", "src"]
|
|
95
|
+
exclude = ["nbs", "tests"]
|