iddqueue 0.13.0rc1__tar.gz → 0.13.0rc3__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.
- iddqueue-0.13.0rc3/PKG-INFO +183 -0
- iddqueue-0.13.0rc3/README.md +162 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/__init__.py +2 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/cli.py +0 -5
- iddqueue-0.13.0rc3/iddqueue/domains.py +70 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/pyproject.toml +4 -2
- iddqueue-0.13.0rc1/PKG-INFO +0 -730
- iddqueue-0.13.0rc1/README.md +0 -709
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/LICENSE +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/broker.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/cancellation.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/cancellation.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/control.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/control.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/coordination.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/deduplication.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/failures.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/history.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/history.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/metrics.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/rate_limits.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/results.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/scheduler.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/scheduler.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/schema.py +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/schema.sql +0 -0
- {iddqueue-0.13.0rc1 → iddqueue-0.13.0rc3}/iddqueue/utils.py +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iddqueue
|
|
3
|
+
Version: 0.13.0rc3
|
|
4
|
+
Summary: Postgres Broker for Dramatiq Task Queue
|
|
5
|
+
Keywords: postgres,task queue,dramatiq
|
|
6
|
+
Author: Étienne BERSAC
|
|
7
|
+
License-Expression: PostgreSQL
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: dramatiq>=2.2.1,<3
|
|
10
|
+
Requires-Dist: psycopg>=3.3.6,<4
|
|
11
|
+
Requires-Dist: psycopg-pool>=3.3.3,<4
|
|
12
|
+
Requires-Dist: tenacity>=9,<10
|
|
13
|
+
Requires-Dist: psycopg[binary]>=3.3.6,<4 ; extra == 'binary'
|
|
14
|
+
Requires-Dist: dramatiq[prometheus]>=2.2.1,<3 ; extra == 'monitoring'
|
|
15
|
+
Requires-Python: >=3.10, <4
|
|
16
|
+
Project-URL: Repository, https://github.com/wa-pis/iddqueue
|
|
17
|
+
Project-URL: Issues, https://github.com/wa-pis/iddqueue/issues
|
|
18
|
+
Provides-Extra: binary
|
|
19
|
+
Provides-Extra: monitoring
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# IDDQueue
|
|
23
|
+
|
|
24
|
+
[Documentation](https://wa-pis.github.io/iddqueue/) · [Step-by-step setup](https://wa-pis.github.io/iddqueue/walkthrough/)
|
|
25
|
+
|
|
26
|
+
A PostgreSQL broker and Results backend for [Dramatiq](https://dramatiq.io/),
|
|
27
|
+
built on synchronous Psycopg 3. Tasks, results and coordination live in PostgreSQL;
|
|
28
|
+
no Redis or ORM is required by IDDQueue.
|
|
29
|
+
|
|
30
|
+
**Current release: [0.13.0rc3](https://pypi.org/project/iddqueue/0.13.0rc3/)** —
|
|
31
|
+
a release candidate for evaluation. [GitHub assets](https://github.com/wa-pis/iddqueue/releases/tag/v0.13.0rc3)
|
|
32
|
+
include the wheel, sdist and SHA256 checksums.
|
|
33
|
+
|
|
34
|
+
IDDQueue is a fork of [DALIBO's dramatiq-pg](https://gitlab.com/dalibo/dramatiq-pg)
|
|
35
|
+
([original package](https://pypi.org/project/dramatiq-pg/)). It preserves the
|
|
36
|
+
PostgreSQL license and original contributor credits.
|
|
37
|
+
|
|
38
|
+
## What it provides
|
|
39
|
+
|
|
40
|
+
- Durable JSONB task/results storage, delayed tasks and crash recovery.
|
|
41
|
+
- Transactional publication alongside business writes; atomic batches and deduplication.
|
|
42
|
+
- PostgreSQL rate limiters, barriers and Dramatiq group callbacks.
|
|
43
|
+
- Pause/resume, cooperative cancellation, failed-task inspection/retry and attempt history.
|
|
44
|
+
- Fixed-interval scheduling and optional Prometheus queue metrics.
|
|
45
|
+
- Schema/prefix isolation and a [tested FastAPI example](docs/fastapi.md).
|
|
46
|
+
|
|
47
|
+
Delivery is **at least once**: actors and callbacks must be idempotent.
|
|
48
|
+
LISTEN/NOTIFY carries message IDs as wakeup hints; consumers claim authoritative
|
|
49
|
+
SQL rows with session advisory locks. See [behavior and limits](docs/user-guide.md).
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
Requires Python 3.10+, Dramatiq 2.2.1+ and Psycopg 3.3.6+.
|
|
54
|
+
CI tests Python **3.10 / 3.13 / 3.14** with PostgreSQL **14 / 18**.
|
|
55
|
+
See [compatibility and API stability](SUPPORT.md).
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
uv venv
|
|
59
|
+
uv pip install "iddqueue[binary]==0.13.0rc3"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The `binary` extra supplies libpq. Base installs require system libpq;
|
|
63
|
+
`[binary,monitoring]` also enables Prometheus support.
|
|
64
|
+
|
|
65
|
+
**Migrating from dramatiq-pg?** Follow the [migration guide](docs/migration.md)
|
|
66
|
+
before changing imports, pools or database storage. Stop all participants,
|
|
67
|
+
back up data, run the upgrade and restart consistently. Fresh initialization
|
|
68
|
+
and an existing-storage upgrade are different operations.
|
|
69
|
+
|
|
70
|
+
## Quickstart
|
|
71
|
+
|
|
72
|
+
Configure PostgreSQL using `PGHOST`, `PGPORT`, `PGUSER`, `PGDATABASE` and your
|
|
73
|
+
normal credential mechanism. Initialize fresh storage:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
uv run --no-sync iddqueue init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For existing storage, use `iddqueue upgrade` after following the migration guide.
|
|
80
|
+
Both commands manage the complete feature schema.
|
|
81
|
+
|
|
82
|
+
Save as `tasks.py`:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import dramatiq
|
|
86
|
+
from iddqueue import PostgresBroker
|
|
87
|
+
|
|
88
|
+
broker = PostgresBroker()
|
|
89
|
+
dramatiq.set_broker(broker)
|
|
90
|
+
|
|
91
|
+
@dramatiq.actor(broker=broker, store_results=True)
|
|
92
|
+
def add(left: int, right: int):
|
|
93
|
+
return left + right
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Start a separate worker from the same directory/environment:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
uv run --no-sync dramatiq --use-spawn --processes=1 --threads=1 tasks
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
In another terminal, publish and read the result:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
uv run --no-sync python - <<'PY'
|
|
106
|
+
from tasks import add, broker
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
message = add.send(2, 3)
|
|
110
|
+
print(message.message_id)
|
|
111
|
+
print(message.get_result(backend=broker.backend, block=True, timeout=10000))
|
|
112
|
+
finally:
|
|
113
|
+
broker.close()
|
|
114
|
+
PY
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The result is `5`; timeouts are milliseconds. Each process creates its own pool.
|
|
118
|
+
Close broker-owned pools on shutdown; callers close pools they supply.
|
|
119
|
+
|
|
120
|
+
## Guides and examples
|
|
121
|
+
|
|
122
|
+
[Domain actors and one worker bootstrap](docs/domains.md) are included since RC3.
|
|
123
|
+
|
|
124
|
+
- [Documentation index](docs/index.md), [user guide](docs/user-guide.md), [API](docs/api.md).
|
|
125
|
+
- [Detailed recipes](docs/recipes.md): transactions, middleware, controls, metrics and schedules.
|
|
126
|
+
- [FastAPI](docs/fastapi.md): lifespan, async endpoint thread offload and separate worker.
|
|
127
|
+
- [Deployment and retention](docs/deployment-guide.md), [why PostgreSQL](docs/why.md).
|
|
128
|
+
- [RC notes](docs/rc-0.13.0rc3.md), [changelog](CHANGELOG.md), [release checks](docs/release.md).
|
|
129
|
+
|
|
130
|
+
The broker and result APIs are synchronous. Async actors use Dramatiq's AsyncIO
|
|
131
|
+
middleware; FastAPI async endpoints offload publication to a thread.
|
|
132
|
+
Transactional enqueue does not accept a Psycopg AsyncConnection.
|
|
133
|
+
|
|
134
|
+
Session-bound locks/listeners require persistent database sessions; PgBouncer
|
|
135
|
+
transaction pooling is unsuitable. Namespace separation is not access control.
|
|
136
|
+
The legacy [django-dramatiq-pg](https://github.com/uptick/django-dramatiq-pg/)
|
|
137
|
+
integration has been archived since September 3, 2024; IDDQueue compatibility
|
|
138
|
+
is unverified. No tested Django integration is currently provided.
|
|
139
|
+
|
|
140
|
+
## Compared with dramatiq-pg
|
|
141
|
+
|
|
142
|
+
Baseline: [dramatiq-pg 0.12.0](https://pypi.org/project/dramatiq-pg/0.12.0/),
|
|
143
|
+
compared with the published IDDQueue 0.13.0rc3 prerelease. This describes the published version, not every
|
|
144
|
+
future upstream revision. Both projects provide a PostgreSQL Dramatiq broker.
|
|
145
|
+
|
|
146
|
+
| Area | dramatiq-pg 0.12.0 | IDDQueue 0.13.0rc3 / practical benefit |
|
|
147
|
+
| --- | --- | --- |
|
|
148
|
+
| Core storage and delivery | JSONB tasks/results, delayed tasks, LISTEN/NOTIFY, advisory locks, recovery and maintenance CLI | Preserved; at-least-once delivery still requires idempotent actors |
|
|
149
|
+
| Actor initialization | Broker configured before actor imports | Opt-in Domain declarations import before DSN; explicit startup registration and domain queues |
|
|
150
|
+
| Runtime | Python >=3.6,<4; Dramatiq >=1.5,<2; Psycopg 2 | Python >=3.10,<4; Dramatiq >=2.2.1,<3; synchronous Psycopg 3 and psycopg-pool |
|
|
151
|
+
| Pool lifecycle | Psycopg 2 pools | Lazy owned pools, explicit close, caller-owned pool support |
|
|
152
|
+
| Transactional publication | Regular enqueue | Caller-owned transaction API: commit business data and tasks together |
|
|
153
|
+
| Coordination | No PostgreSQL rate-limit/barrier backend | PostgreSQL rate limits, durable barriers and standard GroupCallbacks without Redis |
|
|
154
|
+
| Task operations | stats, purge, recover, flush | Failed-task inspection/targeted retry, pause/resume, cooperative cancellation and opt-in attempt history |
|
|
155
|
+
| Publication controls | Single-message enqueue | Deduplication keys/TTL and atomic batches of up to 1000; deduplication is not exactly-once execution |
|
|
156
|
+
| Scheduling | Per-message delay | Also a multi-process fixed-interval scheduler; no cron/calendar expressions |
|
|
157
|
+
| Observability | Basic CLI statistics | Ready/scheduled backlog, task age and optional Prometheus collector |
|
|
158
|
+
| Storage namespaces | Configurable schema/table prefix; shared channel/lock domains | Instance-specific queries and schema/prefix-specific channels/locks; storage separation is not access control |
|
|
159
|
+
| Dramatiq integration | Broker/results implementation | Verified pipelines, groups, AsyncIO and standard middleware; these are Dramatiq features, not a replacement orchestration engine |
|
|
160
|
+
| Compatibility evidence | Historical upstream tests | CI on Python 3.10/3.13/3.14 × PostgreSQL 14/18, functional tests and installed-wheel checks |
|
|
161
|
+
|
|
162
|
+
See [migration from dramatiq-pg](docs/migration.md) for dependency, pool,
|
|
163
|
+
import, CLI and database changes, including backup and rollback. No throughput
|
|
164
|
+
advantage is claimed here. The 0.13.0rc3 prerelease is available on PyPI; the legacy Django
|
|
165
|
+
integration is archived and has not been verified with IDDQueue.
|
|
166
|
+
|
|
167
|
+
## Development and support
|
|
168
|
+
|
|
169
|
+
Use [CONTRIBUTING](CONTRIBUTING.md) for locked uv setup and the full release gate.
|
|
170
|
+
Functional tests require a dedicated PostgreSQL instance: they terminate sessions
|
|
171
|
+
and crash/restart workers. Project planning and evidence live in
|
|
172
|
+
[OpenSpec](openspec/roadmap.md). Report reproducible issues on
|
|
173
|
+
[GitHub](https://github.com/wa-pis/iddqueue/issues).
|
|
174
|
+
|
|
175
|
+
## License and credits
|
|
176
|
+
|
|
177
|
+
Released under the [PostgreSQL license](LICENSE), preserving
|
|
178
|
+
`Copyright (c) 2019, DALIBO` and the original author Étienne BERSAC.
|
|
179
|
+
|
|
180
|
+
Thanks to upstream contributors Andy Freeland, Curtis Maloney (Django support),
|
|
181
|
+
Federico Caselli, Giuseppe Papallo and Rafal Kwasny. The historical upstream logo
|
|
182
|
+
was created by [Damien CAZEILS](http://www.damiencazeils.com/).
|
|
183
|
+
[Original changelog](docs/changelog.rst) remains available as historical context.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# IDDQueue
|
|
2
|
+
|
|
3
|
+
[Documentation](https://wa-pis.github.io/iddqueue/) · [Step-by-step setup](https://wa-pis.github.io/iddqueue/walkthrough/)
|
|
4
|
+
|
|
5
|
+
A PostgreSQL broker and Results backend for [Dramatiq](https://dramatiq.io/),
|
|
6
|
+
built on synchronous Psycopg 3. Tasks, results and coordination live in PostgreSQL;
|
|
7
|
+
no Redis or ORM is required by IDDQueue.
|
|
8
|
+
|
|
9
|
+
**Current release: [0.13.0rc3](https://pypi.org/project/iddqueue/0.13.0rc3/)** —
|
|
10
|
+
a release candidate for evaluation. [GitHub assets](https://github.com/wa-pis/iddqueue/releases/tag/v0.13.0rc3)
|
|
11
|
+
include the wheel, sdist and SHA256 checksums.
|
|
12
|
+
|
|
13
|
+
IDDQueue is a fork of [DALIBO's dramatiq-pg](https://gitlab.com/dalibo/dramatiq-pg)
|
|
14
|
+
([original package](https://pypi.org/project/dramatiq-pg/)). It preserves the
|
|
15
|
+
PostgreSQL license and original contributor credits.
|
|
16
|
+
|
|
17
|
+
## What it provides
|
|
18
|
+
|
|
19
|
+
- Durable JSONB task/results storage, delayed tasks and crash recovery.
|
|
20
|
+
- Transactional publication alongside business writes; atomic batches and deduplication.
|
|
21
|
+
- PostgreSQL rate limiters, barriers and Dramatiq group callbacks.
|
|
22
|
+
- Pause/resume, cooperative cancellation, failed-task inspection/retry and attempt history.
|
|
23
|
+
- Fixed-interval scheduling and optional Prometheus queue metrics.
|
|
24
|
+
- Schema/prefix isolation and a [tested FastAPI example](docs/fastapi.md).
|
|
25
|
+
|
|
26
|
+
Delivery is **at least once**: actors and callbacks must be idempotent.
|
|
27
|
+
LISTEN/NOTIFY carries message IDs as wakeup hints; consumers claim authoritative
|
|
28
|
+
SQL rows with session advisory locks. See [behavior and limits](docs/user-guide.md).
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Requires Python 3.10+, Dramatiq 2.2.1+ and Psycopg 3.3.6+.
|
|
33
|
+
CI tests Python **3.10 / 3.13 / 3.14** with PostgreSQL **14 / 18**.
|
|
34
|
+
See [compatibility and API stability](SUPPORT.md).
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
uv venv
|
|
38
|
+
uv pip install "iddqueue[binary]==0.13.0rc3"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The `binary` extra supplies libpq. Base installs require system libpq;
|
|
42
|
+
`[binary,monitoring]` also enables Prometheus support.
|
|
43
|
+
|
|
44
|
+
**Migrating from dramatiq-pg?** Follow the [migration guide](docs/migration.md)
|
|
45
|
+
before changing imports, pools or database storage. Stop all participants,
|
|
46
|
+
back up data, run the upgrade and restart consistently. Fresh initialization
|
|
47
|
+
and an existing-storage upgrade are different operations.
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
Configure PostgreSQL using `PGHOST`, `PGPORT`, `PGUSER`, `PGDATABASE` and your
|
|
52
|
+
normal credential mechanism. Initialize fresh storage:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
uv run --no-sync iddqueue init
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For existing storage, use `iddqueue upgrade` after following the migration guide.
|
|
59
|
+
Both commands manage the complete feature schema.
|
|
60
|
+
|
|
61
|
+
Save as `tasks.py`:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import dramatiq
|
|
65
|
+
from iddqueue import PostgresBroker
|
|
66
|
+
|
|
67
|
+
broker = PostgresBroker()
|
|
68
|
+
dramatiq.set_broker(broker)
|
|
69
|
+
|
|
70
|
+
@dramatiq.actor(broker=broker, store_results=True)
|
|
71
|
+
def add(left: int, right: int):
|
|
72
|
+
return left + right
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Start a separate worker from the same directory/environment:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
uv run --no-sync dramatiq --use-spawn --processes=1 --threads=1 tasks
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
In another terminal, publish and read the result:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
uv run --no-sync python - <<'PY'
|
|
85
|
+
from tasks import add, broker
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
message = add.send(2, 3)
|
|
89
|
+
print(message.message_id)
|
|
90
|
+
print(message.get_result(backend=broker.backend, block=True, timeout=10000))
|
|
91
|
+
finally:
|
|
92
|
+
broker.close()
|
|
93
|
+
PY
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The result is `5`; timeouts are milliseconds. Each process creates its own pool.
|
|
97
|
+
Close broker-owned pools on shutdown; callers close pools they supply.
|
|
98
|
+
|
|
99
|
+
## Guides and examples
|
|
100
|
+
|
|
101
|
+
[Domain actors and one worker bootstrap](docs/domains.md) are included since RC3.
|
|
102
|
+
|
|
103
|
+
- [Documentation index](docs/index.md), [user guide](docs/user-guide.md), [API](docs/api.md).
|
|
104
|
+
- [Detailed recipes](docs/recipes.md): transactions, middleware, controls, metrics and schedules.
|
|
105
|
+
- [FastAPI](docs/fastapi.md): lifespan, async endpoint thread offload and separate worker.
|
|
106
|
+
- [Deployment and retention](docs/deployment-guide.md), [why PostgreSQL](docs/why.md).
|
|
107
|
+
- [RC notes](docs/rc-0.13.0rc3.md), [changelog](CHANGELOG.md), [release checks](docs/release.md).
|
|
108
|
+
|
|
109
|
+
The broker and result APIs are synchronous. Async actors use Dramatiq's AsyncIO
|
|
110
|
+
middleware; FastAPI async endpoints offload publication to a thread.
|
|
111
|
+
Transactional enqueue does not accept a Psycopg AsyncConnection.
|
|
112
|
+
|
|
113
|
+
Session-bound locks/listeners require persistent database sessions; PgBouncer
|
|
114
|
+
transaction pooling is unsuitable. Namespace separation is not access control.
|
|
115
|
+
The legacy [django-dramatiq-pg](https://github.com/uptick/django-dramatiq-pg/)
|
|
116
|
+
integration has been archived since September 3, 2024; IDDQueue compatibility
|
|
117
|
+
is unverified. No tested Django integration is currently provided.
|
|
118
|
+
|
|
119
|
+
## Compared with dramatiq-pg
|
|
120
|
+
|
|
121
|
+
Baseline: [dramatiq-pg 0.12.0](https://pypi.org/project/dramatiq-pg/0.12.0/),
|
|
122
|
+
compared with the published IDDQueue 0.13.0rc3 prerelease. This describes the published version, not every
|
|
123
|
+
future upstream revision. Both projects provide a PostgreSQL Dramatiq broker.
|
|
124
|
+
|
|
125
|
+
| Area | dramatiq-pg 0.12.0 | IDDQueue 0.13.0rc3 / practical benefit |
|
|
126
|
+
| --- | --- | --- |
|
|
127
|
+
| Core storage and delivery | JSONB tasks/results, delayed tasks, LISTEN/NOTIFY, advisory locks, recovery and maintenance CLI | Preserved; at-least-once delivery still requires idempotent actors |
|
|
128
|
+
| Actor initialization | Broker configured before actor imports | Opt-in Domain declarations import before DSN; explicit startup registration and domain queues |
|
|
129
|
+
| Runtime | Python >=3.6,<4; Dramatiq >=1.5,<2; Psycopg 2 | Python >=3.10,<4; Dramatiq >=2.2.1,<3; synchronous Psycopg 3 and psycopg-pool |
|
|
130
|
+
| Pool lifecycle | Psycopg 2 pools | Lazy owned pools, explicit close, caller-owned pool support |
|
|
131
|
+
| Transactional publication | Regular enqueue | Caller-owned transaction API: commit business data and tasks together |
|
|
132
|
+
| Coordination | No PostgreSQL rate-limit/barrier backend | PostgreSQL rate limits, durable barriers and standard GroupCallbacks without Redis |
|
|
133
|
+
| Task operations | stats, purge, recover, flush | Failed-task inspection/targeted retry, pause/resume, cooperative cancellation and opt-in attempt history |
|
|
134
|
+
| Publication controls | Single-message enqueue | Deduplication keys/TTL and atomic batches of up to 1000; deduplication is not exactly-once execution |
|
|
135
|
+
| Scheduling | Per-message delay | Also a multi-process fixed-interval scheduler; no cron/calendar expressions |
|
|
136
|
+
| Observability | Basic CLI statistics | Ready/scheduled backlog, task age and optional Prometheus collector |
|
|
137
|
+
| Storage namespaces | Configurable schema/table prefix; shared channel/lock domains | Instance-specific queries and schema/prefix-specific channels/locks; storage separation is not access control |
|
|
138
|
+
| Dramatiq integration | Broker/results implementation | Verified pipelines, groups, AsyncIO and standard middleware; these are Dramatiq features, not a replacement orchestration engine |
|
|
139
|
+
| Compatibility evidence | Historical upstream tests | CI on Python 3.10/3.13/3.14 × PostgreSQL 14/18, functional tests and installed-wheel checks |
|
|
140
|
+
|
|
141
|
+
See [migration from dramatiq-pg](docs/migration.md) for dependency, pool,
|
|
142
|
+
import, CLI and database changes, including backup and rollback. No throughput
|
|
143
|
+
advantage is claimed here. The 0.13.0rc3 prerelease is available on PyPI; the legacy Django
|
|
144
|
+
integration is archived and has not been verified with IDDQueue.
|
|
145
|
+
|
|
146
|
+
## Development and support
|
|
147
|
+
|
|
148
|
+
Use [CONTRIBUTING](CONTRIBUTING.md) for locked uv setup and the full release gate.
|
|
149
|
+
Functional tests require a dedicated PostgreSQL instance: they terminate sessions
|
|
150
|
+
and crash/restart workers. Project planning and evidence live in
|
|
151
|
+
[OpenSpec](openspec/roadmap.md). Report reproducible issues on
|
|
152
|
+
[GitHub](https://github.com/wa-pis/iddqueue/issues).
|
|
153
|
+
|
|
154
|
+
## License and credits
|
|
155
|
+
|
|
156
|
+
Released under the [PostgreSQL license](LICENSE), preserving
|
|
157
|
+
`Copyright (c) 2019, DALIBO` and the original author Étienne BERSAC.
|
|
158
|
+
|
|
159
|
+
Thanks to upstream contributors Andy Freeland, Curtis Maloney (Django support),
|
|
160
|
+
Federico Caselli, Giuseppe Papallo and Rafal Kwasny. The historical upstream logo
|
|
161
|
+
was created by [Damien CAZEILS](http://www.damiencazeils.com/).
|
|
162
|
+
[Original changelog](docs/changelog.rst) remains available as historical context.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from .broker import PostgresBroker
|
|
2
2
|
from .cancellation import ResultCancelled
|
|
3
|
+
from .domains import Domain
|
|
3
4
|
from .rate_limits import PostgresRateLimiterBackend
|
|
4
5
|
from .results import PostgresBackend
|
|
5
6
|
from .schema import generate_coordination_sql, generate_init_sql, generate_upgrade_sql
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
9
|
+
"Domain",
|
|
8
10
|
"ResultCancelled",
|
|
9
11
|
"PostgresBackend",
|
|
10
12
|
"PostgresBroker",
|
|
@@ -114,7 +114,6 @@ def make_argument_parser():
|
|
|
114
114
|
"-d",
|
|
115
115
|
"--dsn",
|
|
116
116
|
"--connstring",
|
|
117
|
-
action="store",
|
|
118
117
|
dest="url",
|
|
119
118
|
default="",
|
|
120
119
|
metavar="CONNSTRING",
|
|
@@ -122,8 +121,6 @@ def make_argument_parser():
|
|
|
122
121
|
)
|
|
123
122
|
parser.add_argument(
|
|
124
123
|
"--schemaname",
|
|
125
|
-
action="store",
|
|
126
|
-
dest="schemaname",
|
|
127
124
|
default="dramatiq",
|
|
128
125
|
metavar="SCHEMA",
|
|
129
126
|
help=(
|
|
@@ -132,8 +129,6 @@ def make_argument_parser():
|
|
|
132
129
|
)
|
|
133
130
|
parser.add_argument(
|
|
134
131
|
"--prefix",
|
|
135
|
-
action="store",
|
|
136
|
-
dest="prefix",
|
|
137
132
|
default="",
|
|
138
133
|
metavar="PREFIX",
|
|
139
134
|
help='Prefix for table name for message. Default is "%(default)s".',
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Framework-independent declarations, bound explicitly before worker startup."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from dramatiq import Actor
|
|
6
|
+
from dramatiq.broker import Broker
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class _DeclarationBroker(Broker):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__(middleware=[])
|
|
12
|
+
|
|
13
|
+
def declare_queue(self, queue_name):
|
|
14
|
+
# Declarations create no transport resources.
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def enqueue(self, message, *, delay=None):
|
|
18
|
+
raise RuntimeError("Register the actor's Domain with a broker before sending")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Domain:
|
|
22
|
+
"""One queue and qualified actor names; register once per process."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, name):
|
|
25
|
+
if not isinstance(name, str) or not re.fullmatch(r"[a-zA-Z_][a-zA-Z0-9._-]*", name):
|
|
26
|
+
raise ValueError("domain name must be a valid Dramatiq queue name")
|
|
27
|
+
self.name = name
|
|
28
|
+
self._declarations = _DeclarationBroker()
|
|
29
|
+
self._broker = None
|
|
30
|
+
self._failed = False
|
|
31
|
+
|
|
32
|
+
def actor(self, fn=None, *, actor_name=None, priority=0, **options):
|
|
33
|
+
def decorate(fn):
|
|
34
|
+
if self._broker is not None or self._failed:
|
|
35
|
+
raise RuntimeError("Declare all domain actors before registration")
|
|
36
|
+
if "broker" in options or "queue_name" in options:
|
|
37
|
+
raise ValueError("Domain owns the broker and queue_name")
|
|
38
|
+
name = actor_name if actor_name is not None else fn.__name__
|
|
39
|
+
if not isinstance(name, str) or not name:
|
|
40
|
+
raise ValueError("actor_name must be a nonempty string")
|
|
41
|
+
return Actor(fn, broker=self._declarations, actor_name=f"{self.name}.{name}",
|
|
42
|
+
queue_name=self.name, priority=priority, options=dict(options))
|
|
43
|
+
return decorate if fn is None else decorate(fn)
|
|
44
|
+
|
|
45
|
+
def register(self, broker):
|
|
46
|
+
if self._failed:
|
|
47
|
+
raise RuntimeError("Registration failed; create a new Domain and broker")
|
|
48
|
+
if not isinstance(broker, Broker):
|
|
49
|
+
raise TypeError("register requires a Dramatiq Broker")
|
|
50
|
+
if broker is self._broker:
|
|
51
|
+
return
|
|
52
|
+
if self._broker is not None:
|
|
53
|
+
raise RuntimeError("Domain is already registered with another broker")
|
|
54
|
+
actors = list(self._declarations.actors.values())
|
|
55
|
+
for actor in actors:
|
|
56
|
+
invalid = set(actor.options) - broker.actor_options
|
|
57
|
+
if invalid:
|
|
58
|
+
raise ValueError(f"Undefined actor options for {actor.actor_name}: {sorted(invalid)}")
|
|
59
|
+
if actor.actor_name in broker.actors:
|
|
60
|
+
raise ValueError(f"Actor {actor.actor_name!r} is already registered")
|
|
61
|
+
try:
|
|
62
|
+
for actor in actors:
|
|
63
|
+
actor.broker = broker
|
|
64
|
+
broker.declare_actor(actor)
|
|
65
|
+
except Exception:
|
|
66
|
+
for actor in actors:
|
|
67
|
+
actor.broker = self._declarations
|
|
68
|
+
self._failed = True
|
|
69
|
+
raise
|
|
70
|
+
self._broker = broker
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "iddqueue"
|
|
3
|
-
version = "0.13.
|
|
3
|
+
version = "0.13.0rc3"
|
|
4
4
|
description = "Postgres Broker for Dramatiq Task Queue"
|
|
5
5
|
authors = [{name = "Étienne BERSAC"}]
|
|
6
6
|
license = "PostgreSQL"
|
|
@@ -29,12 +29,14 @@ iddqueue = "iddqueue.cli:entrypoint"
|
|
|
29
29
|
[dependency-groups]
|
|
30
30
|
dev = [
|
|
31
31
|
"pytest>=8", "pytest-timeout>=2", "pytest-mock>=3",
|
|
32
|
-
"
|
|
32
|
+
"psycopg[binary]>=3.3.6,<4",
|
|
33
33
|
"docutils>=0.21", "pygments>=2.20", "ruff>=0.9",
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
fastapi-example = ["fastapi>=0.115,<1", "httpx>=0.28,<1", "uvicorn>=0.34,<1"]
|
|
37
37
|
|
|
38
|
+
docs = ["mkdocs>=1.6.1,<2"]
|
|
39
|
+
|
|
38
40
|
[build-system]
|
|
39
41
|
requires = ["uv_build>=0.11.23,<0.12"]
|
|
40
42
|
build-backend = "uv_build"
|