rrq 0.2.5__tar.gz → 0.3.6__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.
- rrq-0.3.6/.coverage +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/.gitignore +2 -1
- rrq-0.3.6/FUTURE.md +33 -0
- {rrq-0.2.5 → rrq-0.3.6}/PKG-INFO +14 -10
- {rrq-0.2.5 → rrq-0.3.6}/README.md +12 -9
- {rrq-0.2.5 → rrq-0.3.6}/pyproject.toml +4 -3
- rrq-0.3.6/rrq/cli.py +532 -0
- {rrq-0.2.5 → rrq-0.3.6}/rrq/client.py +40 -17
- {rrq-0.2.5 → rrq-0.3.6}/rrq/constants.py +1 -0
- {rrq-0.2.5 → rrq-0.3.6}/rrq/job.py +0 -26
- {rrq-0.2.5 → rrq-0.3.6}/rrq/registry.py +0 -3
- {rrq-0.2.5 → rrq-0.3.6}/rrq/settings.py +2 -3
- {rrq-0.2.5 → rrq-0.3.6}/rrq/store.py +61 -26
- {rrq-0.2.5 → rrq-0.3.6}/rrq/worker.py +17 -3
- rrq-0.3.6/tests/test_cli.py +553 -0
- {rrq-0.2.5 → rrq-0.3.6}/tests/test_client.py +147 -5
- {rrq-0.2.5 → rrq-0.3.6}/tests/test_registry.py +0 -3
- {rrq-0.2.5 → rrq-0.3.6}/tests/test_store.py +38 -2
- {rrq-0.2.5 → rrq-0.3.6}/tests/test_worker.py +118 -22
- {rrq-0.2.5 → rrq-0.3.6}/uv.lock +110 -1
- rrq-0.2.5/rrq/rrq.py +0 -328
- rrq-0.2.5/tests/test_cli.py +0 -259
- {rrq-0.2.5 → rrq-0.3.6}/LICENSE +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/MANIFEST.in +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/example/example_rrq_settings.py +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/example/rrq_example.py +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/rrq/__init__.py +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/rrq/exc.py +0 -0
- {rrq-0.2.5 → rrq-0.3.6}/tests/__init__.py +0 -0
rrq-0.3.6/.coverage
ADDED
|
Binary file
|
rrq-0.3.6/FUTURE.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# RRQ Multi-Worker Safety
|
|
2
|
+
|
|
3
|
+
The core coordination primitives in RRQ are already designed for safe fan-out over multiple worker processes:
|
|
4
|
+
|
|
5
|
+
- Jobs live in a Redis ZSET, with workers atomically acquiring a per-job lock (`SET NX PX`) before removing (`ZREM`) the job ID and executing it
|
|
6
|
+
- The lock ensures that even if two workers race on the same job, only one proceeds past the `SET NX`
|
|
7
|
+
- Once removed from the ZSET, the job can't re-appear until a retry or DLQ–requeue
|
|
8
|
+
- Heartbeats and health keys are namespaced by worker ID (PID+UUID), so many workers can register themselves independently
|
|
9
|
+
|
|
10
|
+
## Areas to Watch in Large Worker Fleets
|
|
11
|
+
|
|
12
|
+
### 1. Two-step Lock+Pop Isn't Fully Atomic
|
|
13
|
+
- If a worker acquires the lock but crashes before `ZREM`, the job stays in the queue until the lock TTL expires, and then another worker can grab it
|
|
14
|
+
- In practice it's rare (must crash in that tiny window), but you can eliminate it by bundling "pop from ZSET + set lock" in a single Lua script
|
|
15
|
+
|
|
16
|
+
### 2. Lock TTL vs. Job Duration
|
|
17
|
+
- We set the lock TTL = `job_timeout + default_lock_timeout_extension_seconds`. If your handlers sometimes exceed that window, the lock can expire mid-run (though the job isn't in the queue anymore)
|
|
18
|
+
- Consider increasing the extension, or implementing a "lock refresher" for very long tasks
|
|
19
|
+
|
|
20
|
+
### 3. Graceful Shutdown & Task Drain
|
|
21
|
+
- Workers will stop polling in burst mode or on a shutdown signal, then "drain" in-flight tasks up to `worker_shutdown_grace_period_seconds`
|
|
22
|
+
- Beyond that they cancel. Make sure your handlers handle `CancelledError` gracefully
|
|
23
|
+
|
|
24
|
+
### 4. Logging & Observability
|
|
25
|
+
- If you're tailing stdout/stderr from many workers, add the worker ID (and queue list) to your log formatter to keep things straight
|
|
26
|
+
|
|
27
|
+
### 5. Health-Check TTLs
|
|
28
|
+
- The heartbeat loop writes a Redis key with a buffer TTL
|
|
29
|
+
- If your network is flaky or your workers get paused (e.g. in a debugger), you may see transient "missing" health keys
|
|
30
|
+
|
|
31
|
+
## Summary
|
|
32
|
+
|
|
33
|
+
With these caveats in mind, you can absolutely spin up dozens (or hundreds) of RRQ worker processes against the same Redis instance, each pulling from the same or different queue names. The locking, queueing, and retry/DLQ logic will keep them from stepping on each other.
|
{rrq-0.2.5 → rrq-0.3.6}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rrq
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: RRQ is a Python library for creating reliable job queues using Redis and asyncio
|
|
5
5
|
Project-URL: Homepage, https://github.com/getresq/rrq
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/getresq/rrq/issues
|
|
@@ -21,17 +21,12 @@ Requires-Dist: redis[hiredis]<6,>=4.2.0
|
|
|
21
21
|
Requires-Dist: watchfiles>=0.19.0
|
|
22
22
|
Provides-Extra: dev
|
|
23
23
|
Requires-Dist: pytest-asyncio>=0.26.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
24
25
|
Requires-Dist: pytest>=8.3.5; extra == 'dev'
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
26
27
|
|
|
27
28
|
# RRQ: Reliable Redis Queue
|
|
28
29
|
|
|
29
|
-
____ ____ ___
|
|
30
|
-
| _ \ | _ \ / _ \
|
|
31
|
-
| |_) | | |_) | | | | |
|
|
32
|
-
| _ < | _ < | |_| |
|
|
33
|
-
|_| \_\ |_| \_\ \__\_\
|
|
34
|
-
|
|
35
30
|
RRQ is a Python library for creating reliable job queues using Redis and `asyncio`, inspired by [ARQ (Async Redis Queue)](https://github.com/samuelcolvin/arq). It focuses on providing at-least-once job processing semantics with features like automatic retries, job timeouts, dead-letter queues, and graceful worker shutdown.
|
|
36
31
|
|
|
37
32
|
## Core Components
|
|
@@ -58,10 +53,20 @@ RRQ is a Python library for creating reliable job queues using Redis and `asynci
|
|
|
58
53
|
* **Worker Health Checks**: Workers periodically update a health key in Redis with a TTL, allowing monitoring systems to track active workers.
|
|
59
54
|
* **Deferred Execution**: Jobs can be scheduled to run at a future time using `_defer_by` or `_defer_until`.
|
|
60
55
|
*Note: Using deferral with a specific `_job_id` will effectively reschedule the job associated with that ID to the new time, overwriting its previous definition and score. It does not create multiple distinct scheduled jobs with the same ID.*
|
|
56
|
+
*To batch multiple enqueue calls into a single deferred job (and prevent duplicates within the defer window), combine `_unique_key` with `_defer_by`. For example:*
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
await client.enqueue(
|
|
60
|
+
"process_updates",
|
|
61
|
+
item_id=123,
|
|
62
|
+
_unique_key="update:123",
|
|
63
|
+
_defer_by=10,
|
|
64
|
+
)
|
|
65
|
+
```
|
|
61
66
|
|
|
62
67
|
## Basic Usage
|
|
63
68
|
|
|
64
|
-
*(See [`rrq_example.py`](
|
|
69
|
+
*(See [`rrq_example.py`](https://github.com/GetResQ/rrq/tree/master/example) in the project root for a runnable example)*
|
|
65
70
|
|
|
66
71
|
**1. Define Handlers:**
|
|
67
72
|
|
|
@@ -165,10 +170,9 @@ rrq <command> [options]
|
|
|
165
170
|
|
|
166
171
|
- **`worker run`**: Run an RRQ worker process to process jobs from queues.
|
|
167
172
|
```bash
|
|
168
|
-
rrq worker run [--burst]
|
|
173
|
+
rrq worker run [--burst] --settings <settings_path>
|
|
169
174
|
```
|
|
170
175
|
- `--burst`: Run in burst mode (process one job/batch then exit).
|
|
171
|
-
- `--detach`: Run the worker in the background.
|
|
172
176
|
- `--settings`: Python settings path for application worker settings (e.g., `myapp.worker_config.rrq_settings`).
|
|
173
177
|
|
|
174
178
|
- **`worker watch`**: Run an RRQ worker with auto-restart on file changes in a specified directory.
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
# RRQ: Reliable Redis Queue
|
|
2
2
|
|
|
3
|
-
____ ____ ___
|
|
4
|
-
| _ \ | _ \ / _ \
|
|
5
|
-
| |_) | | |_) | | | | |
|
|
6
|
-
| _ < | _ < | |_| |
|
|
7
|
-
|_| \_\ |_| \_\ \__\_\
|
|
8
|
-
|
|
9
3
|
RRQ is a Python library for creating reliable job queues using Redis and `asyncio`, inspired by [ARQ (Async Redis Queue)](https://github.com/samuelcolvin/arq). It focuses on providing at-least-once job processing semantics with features like automatic retries, job timeouts, dead-letter queues, and graceful worker shutdown.
|
|
10
4
|
|
|
11
5
|
## Core Components
|
|
@@ -32,10 +26,20 @@ RRQ is a Python library for creating reliable job queues using Redis and `asynci
|
|
|
32
26
|
* **Worker Health Checks**: Workers periodically update a health key in Redis with a TTL, allowing monitoring systems to track active workers.
|
|
33
27
|
* **Deferred Execution**: Jobs can be scheduled to run at a future time using `_defer_by` or `_defer_until`.
|
|
34
28
|
*Note: Using deferral with a specific `_job_id` will effectively reschedule the job associated with that ID to the new time, overwriting its previous definition and score. It does not create multiple distinct scheduled jobs with the same ID.*
|
|
29
|
+
*To batch multiple enqueue calls into a single deferred job (and prevent duplicates within the defer window), combine `_unique_key` with `_defer_by`. For example:*
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
await client.enqueue(
|
|
33
|
+
"process_updates",
|
|
34
|
+
item_id=123,
|
|
35
|
+
_unique_key="update:123",
|
|
36
|
+
_defer_by=10,
|
|
37
|
+
)
|
|
38
|
+
```
|
|
35
39
|
|
|
36
40
|
## Basic Usage
|
|
37
41
|
|
|
38
|
-
*(See [`rrq_example.py`](
|
|
42
|
+
*(See [`rrq_example.py`](https://github.com/GetResQ/rrq/tree/master/example) in the project root for a runnable example)*
|
|
39
43
|
|
|
40
44
|
**1. Define Handlers:**
|
|
41
45
|
|
|
@@ -139,10 +143,9 @@ rrq <command> [options]
|
|
|
139
143
|
|
|
140
144
|
- **`worker run`**: Run an RRQ worker process to process jobs from queues.
|
|
141
145
|
```bash
|
|
142
|
-
rrq worker run [--burst]
|
|
146
|
+
rrq worker run [--burst] --settings <settings_path>
|
|
143
147
|
```
|
|
144
148
|
- `--burst`: Run in burst mode (process one job/batch then exit).
|
|
145
|
-
- `--detach`: Run the worker in the background.
|
|
146
149
|
- `--settings`: Python settings path for application worker settings (e.g., `myapp.worker_config.rrq_settings`).
|
|
147
150
|
|
|
148
151
|
- **`worker watch`**: Run an RRQ worker with auto-restart on file changes in a specified directory.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rrq"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.6"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "Mazdak Rezvani", email = "mazdak@me.com" },
|
|
10
10
|
]
|
|
@@ -33,6 +33,7 @@ dependencies = [
|
|
|
33
33
|
dev = [
|
|
34
34
|
"pytest>=8.3.5",
|
|
35
35
|
"pytest-asyncio>=0.26.0",
|
|
36
|
+
"pytest-cov>=6.0.0",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
[project.urls]
|
|
@@ -40,7 +41,7 @@ dev = [
|
|
|
40
41
|
"Bug Tracker" = "https://github.com/getresq/rrq/issues"
|
|
41
42
|
|
|
42
43
|
[project.scripts]
|
|
43
|
-
rrq = "rrq.
|
|
44
|
+
rrq = "rrq.cli:rrq"
|
|
44
45
|
|
|
45
46
|
[tool.pytest.ini_options]
|
|
46
|
-
asyncio_default_fixture_loop_scope = "function"
|
|
47
|
+
asyncio_default_fixture_loop_scope = "function"
|