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 ADDED
Binary file
@@ -1,3 +1,4 @@
1
1
  .venv/
2
2
  __pycache__/
3
- .git/
3
+ .git/
4
+ .vscode/
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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rrq
3
- Version: 0.2.5
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`](examples/rrq_example.py) in the project root for a runnable example)*
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] [--detach] --settings <settings_path>
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`](examples/rrq_example.py) in the project root for a runnable example)*
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] [--detach] --settings <settings_path>
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.2.5"
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.rrq:rrq" # Assumes rrq.py is at the root of your source directory
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"