redqueue 0.13.1__tar.gz → 0.14.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.
- {redqueue-0.13.1 → redqueue-0.14.0}/CHANGELOG.md +33 -15
- {redqueue-0.13.1 → redqueue-0.14.0}/PKG-INFO +30 -7
- {redqueue-0.13.1 → redqueue-0.14.0}/README-zh-CN.md +38 -18
- {redqueue-0.13.1 → redqueue-0.14.0}/README.md +42 -19
- {redqueue-0.13.1 → redqueue-0.14.0}/docs/API.md +54 -17
- redqueue-0.14.0/docs/superpowers/plans/2026-06-27-message-deduplication.md +357 -0
- redqueue-0.14.0/docs/superpowers/specs/2026-06-27-message-deduplication-design.md +170 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/pyproject.toml +2 -2
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/__init__.py +4 -3
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/_version.py +1 -1
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/async_client.py +117 -52
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/client.py +109 -51
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/config.py +30 -0
- redqueue-0.14.0/src/redqueue/deduplication.py +334 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/message.py +16 -16
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/monitoring.py +4 -3
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/fakes.py +68 -26
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_project_skeleton.py +346 -138
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_real_redis_availability.py +68 -5
- {redqueue-0.13.1 → redqueue-0.14.0}/.github/workflows/ci.yml +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/.gitignore +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/CODE_OF_CONDUCT.md +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/CONTRIBUTING.md +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/LICENSE +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/NOTICE +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/docs/RELEASE.md +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/README.md +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/__init__.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/async_list_queue.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/common.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/compatibility_check.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/custom_serializer.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/delayed_tasks.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/monitoring_hooks.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/stream_queue.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/examples/sync_list_queue.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/requirements.txt +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/scripts/check.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/__main__.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/__init__.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/async_delay.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/async_list.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/async_stream.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/base.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/delay.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/list.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/backends/stream.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/cli.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/compat.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/connection.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/exceptions.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/src/redqueue/serialization.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/README.md +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/__init__.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_availability.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_backend_contracts.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_cli.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_integration_redis.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_performance.py +0 -0
- {redqueue-0.13.1 → redqueue-0.14.0}/tests/test_real_redis_performance.py +0 -0
|
@@ -7,26 +7,44 @@ All notable public release changes are documented here.
|
|
|
7
7
|
Development versions are tracked separately from formal release versions.
|
|
8
8
|
开发版本与正式版本分开管理。
|
|
9
9
|
|
|
10
|
-
## [0.
|
|
11
|
-
|
|
12
|
-
### Fixed
|
|
10
|
+
## [0.14.0] - 2026-06-27
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
`headers["trace_id"]` values could fail to construct or consume after
|
|
16
|
-
upgrading to `0.13.0`.
|
|
17
|
-
- Fixed sync and async `publish(..., delay=..., message_id=...)` so delayed
|
|
18
|
-
publishing preserves caller-provided message ids.
|
|
12
|
+
### Added
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
- Added opt-in Redis-backed message deduplication with
|
|
15
|
+
`DeduplicationConfig`.
|
|
16
|
+
- Added `dedup_key` support to sync and async `publish()` and `delay()`.
|
|
17
|
+
- Added duplicate-hit behavior that returns the first message id without
|
|
18
|
+
enqueueing or scheduling another message.
|
|
19
|
+
- Added `message.deduplicated` monitoring events.
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
消息构造或消费失败的兼容性回归。
|
|
24
|
-
- 修复同步和异步 `publish(..., delay=..., message_id=...)`,现在延迟发布会
|
|
25
|
-
保留调用方传入的消息 ID。
|
|
21
|
+
### 新增
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
- 新增基于 Redis 的可选消息去重能力,通过 `DeduplicationConfig` 启用。
|
|
24
|
+
- 同步和异步 `publish()`、`delay()` 新增 `dedup_key` 参数。
|
|
25
|
+
- 重复命中时返回第一次消息 ID,不再重复入队或重复调度。
|
|
26
|
+
- 新增 `message.deduplicated` 监控事件。
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
## [0.13.1] - 2026-06-27
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed a compatibility regression where legacy messages with blank
|
|
33
|
+
`headers["trace_id"]` values could fail to construct or consume after
|
|
34
|
+
upgrading to `0.13.0`.
|
|
35
|
+
- Fixed sync and async `publish(..., delay=..., message_id=...)` so delayed
|
|
36
|
+
publishing preserves caller-provided message ids.
|
|
37
|
+
|
|
38
|
+
### 修复
|
|
39
|
+
|
|
40
|
+
- 修复升级到 `0.13.0` 后,历史消息中空白 `headers["trace_id"]` 可能导致
|
|
41
|
+
消息构造或消费失败的兼容性回归。
|
|
42
|
+
- 修复同步和异步 `publish(..., delay=..., message_id=...)`,现在延迟发布会
|
|
43
|
+
保留调用方传入的消息 ID。
|
|
44
|
+
|
|
45
|
+
## [0.13.0] - 2026-06-27
|
|
46
|
+
|
|
47
|
+
### Added
|
|
30
48
|
|
|
31
49
|
- Added first-class `trace_id` support to `Message`, sync and async
|
|
32
50
|
`publish()`, sync and async `delay()`, List, Streams, and delayed task
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redqueue
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Redis-backed Python message queue library with List, Streams, delayed tasks, and monitoring.
|
|
3
|
+
Version: 0.14.0
|
|
4
|
+
Summary: Redis-backed Python message queue library with List, Streams, delayed tasks, deduplication, and monitoring.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SpringMirror-pear/redqueue
|
|
6
6
|
Project-URL: Repository, https://github.com/SpringMirror-pear/redqueue.git
|
|
7
7
|
Project-URL: Issues, https://github.com/SpringMirror-pear/redqueue/issues
|
|
@@ -52,6 +52,7 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
52
52
|
- Redis connection pool managers for shared sync and async resources.
|
|
53
53
|
- `redqueue` CLI for local debugging and operational checks.
|
|
54
54
|
- First-class `trace_id` propagation for lifecycle tracing.
|
|
55
|
+
- Opt-in message deduplication with Redis `SET NX` and TTL windows.
|
|
55
56
|
- Unified exception hierarchy with structured context.
|
|
56
57
|
- Monitoring events for publish, consume, ack, nack, retry, dead letter, delay,
|
|
57
58
|
and backend errors.
|
|
@@ -75,6 +76,7 @@ Redis:
|
|
|
75
76
|
| Streams | `>=5.0` | Uses `XADD`, `XGROUP CREATE`, `XREADGROUP` |
|
|
76
77
|
| Streams auto claim | `>=6.2` | Uses `XAUTOCLAIM`; Redis 5.x uses `XPENDING`/`XCLAIM` fallback |
|
|
77
78
|
| Delayed tasks | `>=1.2` | Uses `ZADD` and timestamp scores |
|
|
79
|
+
| Message deduplication | `>=2.6.12` | Uses `SET` with `NX` and `EX`/`PX` |
|
|
78
80
|
|
|
79
81
|
## Installation
|
|
80
82
|
|
|
@@ -210,6 +212,23 @@ client.delay({"to": "later@example.com"}, delay_seconds=60, trace_id="trace-123"
|
|
|
210
212
|
released = client.schedule_due(limit=100)
|
|
211
213
|
```
|
|
212
214
|
|
|
215
|
+
Message deduplication:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
from redqueue import DeduplicationConfig, QueueClient
|
|
219
|
+
|
|
220
|
+
client = QueueClient.from_url(
|
|
221
|
+
"redis://127.0.0.1:6379/0",
|
|
222
|
+
queue="emails",
|
|
223
|
+
deduplication=DeduplicationConfig(enabled=True, ttl_seconds=3600),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
first_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
227
|
+
second_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
228
|
+
|
|
229
|
+
assert second_id == first_id
|
|
230
|
+
```
|
|
231
|
+
|
|
213
232
|
Trace IDs:
|
|
214
233
|
|
|
215
234
|
```python
|
|
@@ -367,17 +386,21 @@ REDQUEUE_REDIS_URL=redis://127.0.0.1:6379/0 PYTHONPATH=src python -m pytest -m "
|
|
|
367
386
|
|
|
368
387
|
Latest local run on Python `3.14.5`:
|
|
369
388
|
|
|
370
|
-
- Full test suite without `REDQUEUE_REDIS_URL`: `
|
|
371
|
-
- Real Redis
|
|
389
|
+
- Full test suite without `REDQUEUE_REDIS_URL`: `114 passed, 10 skipped`.
|
|
390
|
+
- Real Redis integration suite: `10 passed` with
|
|
391
|
+
`redis://127.0.0.1:6379/0`.
|
|
392
|
+
- Real Redis availability suite: `5 passed` with
|
|
372
393
|
`redis://127.0.0.1:6379/0`.
|
|
373
394
|
- Real Redis server: Redis for Windows `5.0.14.1`.
|
|
374
395
|
- Availability suite: covers List processing recovery, List dead-letter
|
|
375
396
|
requeue, Streams Redis `<5.0` compatibility rejection, Streams Redis 5.x
|
|
376
397
|
pending recovery fallback, Streams dead-letter requeue, delayed task publish
|
|
377
|
-
failure rollback, missing delayed payload errors,
|
|
378
|
-
|
|
398
|
+
failure rollback, missing delayed payload errors, publish-time deduplication,
|
|
399
|
+
delayed task deduplication, async List recovery, async Streams dead-letter
|
|
400
|
+
requeue, and async delayed task rollback.
|
|
379
401
|
- Real Redis availability suite additionally validates List recovery, Streams
|
|
380
|
-
dead-letter requeue,
|
|
402
|
+
dead-letter requeue, delayed task rollback, List deduplication, and delayed
|
|
403
|
+
task deduplication against a running Redis server.
|
|
381
404
|
|
|
382
405
|
## Performance Results
|
|
383
406
|
|
|
@@ -15,10 +15,11 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
15
15
|
- 基于 Redis Streams 的消费组后端,Streams 要求 Redis `>=5.0`。
|
|
16
16
|
- 基于 Redis Sorted Set 的延迟任务。
|
|
17
17
|
- 同步客户端 `QueueClient` 与异步客户端 `AsyncQueueClient`。
|
|
18
|
-
- 支持同步和异步 Redis 连接池管理器,方便多个客户端共享连接池。
|
|
19
|
-
- 提供 `redqueue` CLI,用于本地调试和运行时检查。
|
|
20
|
-
- 一等 `trace_id` 链路追踪能力,贯穿消息生命周期。
|
|
21
|
-
-
|
|
18
|
+
- 支持同步和异步 Redis 连接池管理器,方便多个客户端共享连接池。
|
|
19
|
+
- 提供 `redqueue` CLI,用于本地调试和运行时检查。
|
|
20
|
+
- 一等 `trace_id` 链路追踪能力,贯穿消息生命周期。
|
|
21
|
+
- 可选消息去重能力,基于 Redis `SET NX` 和 TTL 窗口。
|
|
22
|
+
- 带结构化上下文的统一异常体系。
|
|
22
23
|
- 针对发布、消费、确认、拒绝、重试、死信、延迟和后端错误的监控事件。
|
|
23
24
|
- 通过 `INFO server` 探测 Redis 能力。
|
|
24
25
|
- Apache License 2.0。
|
|
@@ -37,9 +38,10 @@ Redis:
|
|
|
37
38
|
| --- | --- | --- |
|
|
38
39
|
| List 阻塞消费 | `>=2.0` | 以 `BLPOP` 系列能力为基础 |
|
|
39
40
|
| List 可靠搬移 | `>=2.2` | 使用 `BRPOPLPUSH`;Redis `>=6.2` 优先使用 `BLMOVE` |
|
|
40
|
-
| Streams | `>=5.0` | 使用 `XADD`、`XGROUP CREATE`、`XREADGROUP` |
|
|
41
|
-
| Streams 自动认领 | `>=6.2` | 使用 `XAUTOCLAIM`;Redis 5.x 回退 `XPENDING`/`XCLAIM` |
|
|
42
|
-
| 延迟任务 | `>=1.2` | 使用 `ZADD` 和时间戳 score |
|
|
41
|
+
| Streams | `>=5.0` | 使用 `XADD`、`XGROUP CREATE`、`XREADGROUP` |
|
|
42
|
+
| Streams 自动认领 | `>=6.2` | 使用 `XAUTOCLAIM`;Redis 5.x 回退 `XPENDING`/`XCLAIM` |
|
|
43
|
+
| 延迟任务 | `>=1.2` | 使用 `ZADD` 和时间戳 score |
|
|
44
|
+
| 消息去重 | `>=2.6.12` | 使用带 `NX` 和 `EX`/`PX` 的 `SET` |
|
|
43
45
|
|
|
44
46
|
## 安装
|
|
45
47
|
|
|
@@ -165,17 +167,34 @@ async def main() -> None:
|
|
|
165
167
|
asyncio.run(main())
|
|
166
168
|
```
|
|
167
169
|
|
|
168
|
-
延迟任务:
|
|
170
|
+
延迟任务:
|
|
169
171
|
|
|
170
172
|
```python
|
|
171
173
|
from redqueue import QueueClient
|
|
172
174
|
|
|
173
175
|
client = QueueClient.from_url("redis://127.0.0.1:6379/0", queue="emails")
|
|
174
176
|
client.delay({"to": "later@example.com"}, delay_seconds=60, trace_id="trace-123")
|
|
175
|
-
released = client.schedule_due(limit=100)
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
released = client.schedule_due(limit=100)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
消息去重:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from redqueue import DeduplicationConfig, QueueClient
|
|
184
|
+
|
|
185
|
+
client = QueueClient.from_url(
|
|
186
|
+
"redis://127.0.0.1:6379/0",
|
|
187
|
+
queue="emails",
|
|
188
|
+
deduplication=DeduplicationConfig(enabled=True, ttl_seconds=3600),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
first_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
192
|
+
second_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
193
|
+
|
|
194
|
+
assert second_id == first_id
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
链路追踪:
|
|
179
198
|
|
|
180
199
|
```python
|
|
181
200
|
from redqueue import InMemoryMonitoringHook, QueueClient, new_trace_id
|
|
@@ -329,15 +348,16 @@ REDQUEUE_REDIS_URL=redis://127.0.0.1:6379/0 PYTHONPATH=src python -m pytest -m "
|
|
|
329
348
|
|
|
330
349
|
Python `3.14.5` 最新本地运行结果:
|
|
331
350
|
|
|
332
|
-
- 未设置 `REDQUEUE_REDIS_URL` 时的完整测试套件:`
|
|
333
|
-
- 真实 Redis
|
|
351
|
+
- 未设置 `REDQUEUE_REDIS_URL` 时的完整测试套件:`114 passed, 10 skipped`。
|
|
352
|
+
- 真实 Redis 集成套件:使用 `redis://127.0.0.1:6379/0` 时 `10 passed`。
|
|
353
|
+
- 真实 Redis 可用性套件:使用 `redis://127.0.0.1:6379/0` 时 `5 passed`。
|
|
334
354
|
- 真实 Redis 服务端:Redis for Windows `5.0.14.1`。
|
|
335
355
|
- 可用性套件覆盖:List processing 恢复、List 死信重放、Streams Redis
|
|
336
356
|
`<5.0` 兼容性拒绝、Streams Redis 5.x pending 恢复回退、Streams 死信
|
|
337
|
-
重放、延迟任务发布失败回滚、延迟 payload
|
|
338
|
-
Streams 死信重放和异步延迟任务回滚。
|
|
339
|
-
- 真实 Redis 可用性套件额外验证了运行中 Redis 服务上的 List 恢复、Streams
|
|
340
|
-
|
|
357
|
+
重放、延迟任务发布失败回滚、延迟 payload 缺失错误、发布时去重、延迟任务
|
|
358
|
+
去重、异步 List 恢复、异步 Streams 死信重放和异步延迟任务回滚。
|
|
359
|
+
- 真实 Redis 可用性套件额外验证了运行中 Redis 服务上的 List 恢复、Streams
|
|
360
|
+
死信重放、延迟任务回滚、List 去重和延迟任务去重。
|
|
341
361
|
|
|
342
362
|
## 性能测试结果
|
|
343
363
|
|
|
@@ -16,10 +16,11 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
16
16
|
- Redis Streams backend with consumer groups. Streams require Redis `>=5.0`.
|
|
17
17
|
- Delayed tasks based on Redis Sorted Set.
|
|
18
18
|
- Sync client `QueueClient` and async client `AsyncQueueClient`.
|
|
19
|
-
- Redis connection pool managers for shared sync and async resources.
|
|
20
|
-
- `redqueue` CLI for local debugging and operational checks.
|
|
21
|
-
- First-class `trace_id` propagation for lifecycle tracing.
|
|
22
|
-
-
|
|
19
|
+
- Redis connection pool managers for shared sync and async resources.
|
|
20
|
+
- `redqueue` CLI for local debugging and operational checks.
|
|
21
|
+
- First-class `trace_id` propagation for lifecycle tracing.
|
|
22
|
+
- Opt-in message deduplication with Redis `SET NX` and TTL windows.
|
|
23
|
+
- Unified exception hierarchy with structured context.
|
|
23
24
|
- Monitoring events for publish, consume, ack, nack, retry, dead letter, delay,
|
|
24
25
|
and backend errors.
|
|
25
26
|
- Redis capability detection from `INFO server`.
|
|
@@ -39,9 +40,10 @@ Redis:
|
|
|
39
40
|
| --- | --- | --- |
|
|
40
41
|
| List blocking consume | `>=2.0` | Uses `BLPOP` family compatibility baseline |
|
|
41
42
|
| List reliable move | `>=2.2` | Uses `BRPOPLPUSH`; `BLMOVE` preferred on `>=6.2` |
|
|
42
|
-
| Streams | `>=5.0` | Uses `XADD`, `XGROUP CREATE`, `XREADGROUP` |
|
|
43
|
-
| Streams auto claim | `>=6.2` | Uses `XAUTOCLAIM`; Redis 5.x uses `XPENDING`/`XCLAIM` fallback |
|
|
44
|
-
| Delayed tasks | `>=1.2` | Uses `ZADD` and timestamp scores |
|
|
43
|
+
| Streams | `>=5.0` | Uses `XADD`, `XGROUP CREATE`, `XREADGROUP` |
|
|
44
|
+
| Streams auto claim | `>=6.2` | Uses `XAUTOCLAIM`; Redis 5.x uses `XPENDING`/`XCLAIM` fallback |
|
|
45
|
+
| Delayed tasks | `>=1.2` | Uses `ZADD` and timestamp scores |
|
|
46
|
+
| Message deduplication | `>=2.6.12` | Uses `SET` with `NX` and `EX`/`PX` |
|
|
45
47
|
|
|
46
48
|
## Installation
|
|
47
49
|
|
|
@@ -167,17 +169,34 @@ async def main() -> None:
|
|
|
167
169
|
asyncio.run(main())
|
|
168
170
|
```
|
|
169
171
|
|
|
170
|
-
Delayed task:
|
|
172
|
+
Delayed task:
|
|
171
173
|
|
|
172
174
|
```python
|
|
173
175
|
from redqueue import QueueClient
|
|
174
176
|
|
|
175
177
|
client = QueueClient.from_url("redis://127.0.0.1:6379/0", queue="emails")
|
|
176
178
|
client.delay({"to": "later@example.com"}, delay_seconds=60, trace_id="trace-123")
|
|
177
|
-
released = client.schedule_due(limit=100)
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
released = client.schedule_due(limit=100)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Message deduplication:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
from redqueue import DeduplicationConfig, QueueClient
|
|
186
|
+
|
|
187
|
+
client = QueueClient.from_url(
|
|
188
|
+
"redis://127.0.0.1:6379/0",
|
|
189
|
+
queue="emails",
|
|
190
|
+
deduplication=DeduplicationConfig(enabled=True, ttl_seconds=3600),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
first_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
194
|
+
second_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
195
|
+
|
|
196
|
+
assert second_id == first_id
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Trace IDs:
|
|
181
200
|
|
|
182
201
|
```python
|
|
183
202
|
from redqueue import InMemoryMonitoringHook, QueueClient, new_trace_id
|
|
@@ -334,17 +353,21 @@ REDQUEUE_REDIS_URL=redis://127.0.0.1:6379/0 PYTHONPATH=src python -m pytest -m "
|
|
|
334
353
|
|
|
335
354
|
Latest local run on Python `3.14.5`:
|
|
336
355
|
|
|
337
|
-
- Full test suite without `REDQUEUE_REDIS_URL`: `
|
|
338
|
-
- Real Redis
|
|
339
|
-
`redis://127.0.0.1:6379/0`.
|
|
356
|
+
- Full test suite without `REDQUEUE_REDIS_URL`: `114 passed, 10 skipped`.
|
|
357
|
+
- Real Redis integration suite: `10 passed` with
|
|
358
|
+
`redis://127.0.0.1:6379/0`.
|
|
359
|
+
- Real Redis availability suite: `5 passed` with
|
|
360
|
+
`redis://127.0.0.1:6379/0`.
|
|
340
361
|
- Real Redis server: Redis for Windows `5.0.14.1`.
|
|
341
362
|
- Availability suite: covers List processing recovery, List dead-letter
|
|
342
363
|
requeue, Streams Redis `<5.0` compatibility rejection, Streams Redis 5.x
|
|
343
364
|
pending recovery fallback, Streams dead-letter requeue, delayed task publish
|
|
344
|
-
failure rollback, missing delayed payload errors,
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
365
|
+
failure rollback, missing delayed payload errors, publish-time deduplication,
|
|
366
|
+
delayed task deduplication, async List recovery, async Streams dead-letter
|
|
367
|
+
requeue, and async delayed task rollback.
|
|
368
|
+
- Real Redis availability suite additionally validates List recovery, Streams
|
|
369
|
+
dead-letter requeue, delayed task rollback, List deduplication, and delayed
|
|
370
|
+
task deduplication against a running Redis server.
|
|
348
371
|
|
|
349
372
|
## Performance Results
|
|
350
373
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# RedQueue API / RedQueue API 文档
|
|
2
2
|
|
|
3
|
-
This document describes the public API available in RedQueue `0.
|
|
3
|
+
This document describes the public API available in RedQueue `0.14.0`.
|
|
4
4
|
|
|
5
|
-
本文档描述 RedQueue `0.
|
|
5
|
+
本文档描述 RedQueue `0.14.0` 的公开 API。
|
|
6
6
|
|
|
7
7
|
## Clients / 客户端
|
|
8
8
|
|
|
@@ -27,12 +27,12 @@ Methods / 方法:
|
|
|
27
27
|
- `from_url(url, *, queue, backend="list", connection_manager=None, **options) -> QueueClient`
|
|
28
28
|
- Advanced options include `pool_options`, injected `redis`, injected
|
|
29
29
|
`capabilities`, and `owns_redis`.
|
|
30
|
-
- `publish(payload, *, delay=None, headers=None, message_id=None, trace_id=None) -> str`
|
|
30
|
+
- `publish(payload, *, delay=None, headers=None, message_id=None, trace_id=None, dedup_key=None) -> str`
|
|
31
31
|
- `consume(*, timeout=None, batch_size=1) -> Message | list[Message] | None`
|
|
32
32
|
- `ack(message) -> None`
|
|
33
33
|
- `nack(message, *, requeue=True) -> None`
|
|
34
34
|
- `retry(message, *, delay=None, reason=None) -> None`
|
|
35
|
-
- `delay(payload, *, delay_seconds=None, run_at=None, headers=None, message_id=None, trace_id=None) -> str`
|
|
35
|
+
- `delay(payload, *, delay_seconds=None, run_at=None, headers=None, message_id=None, trace_id=None, dedup_key=None) -> str`
|
|
36
36
|
- `schedule_due(*, limit=100, now=None) -> int`
|
|
37
37
|
- `recover_stale(*, min_idle_ms=None, limit=100) -> int`
|
|
38
38
|
- `dead_letters(*, limit=100) -> list[Message]`
|
|
@@ -61,12 +61,12 @@ Methods / 方法:
|
|
|
61
61
|
- `await from_url(url, *, queue, backend="list", connection_manager=None, **options) -> AsyncQueueClient`
|
|
62
62
|
- Advanced options include `pool_options`, injected `redis`, injected
|
|
63
63
|
`capabilities`, and `owns_redis`.
|
|
64
|
-
- `await publish(payload, *, delay=None, headers=None, message_id=None, trace_id=None) -> str`
|
|
64
|
+
- `await publish(payload, *, delay=None, headers=None, message_id=None, trace_id=None, dedup_key=None) -> str`
|
|
65
65
|
- `await consume(*, timeout=None, batch_size=1) -> Message | list[Message] | None`
|
|
66
66
|
- `await ack(message) -> None`
|
|
67
67
|
- `await nack(message, *, requeue=True) -> None`
|
|
68
68
|
- `await retry(message, *, delay=None, reason=None) -> None`
|
|
69
|
-
- `await delay(payload, *, delay_seconds=None, run_at=None, headers=None, message_id=None, trace_id=None) -> str`
|
|
69
|
+
- `await delay(payload, *, delay_seconds=None, run_at=None, headers=None, message_id=None, trace_id=None, dedup_key=None) -> str`
|
|
70
70
|
- `await schedule_due(*, limit=100, now=None) -> int`
|
|
71
71
|
- `await recover_stale(*, min_idle_ms=None, limit=100) -> int`
|
|
72
72
|
- `await dead_letters(*, limit=100) -> list[Message]`
|
|
@@ -147,9 +147,10 @@ Important fields / 重要字段:
|
|
|
147
147
|
- `queue: str`
|
|
148
148
|
- `backend: BackendType | str = BackendType.LIST`
|
|
149
149
|
- `enable_delay: bool = False`
|
|
150
|
-
- `namespace: str = "rq"`
|
|
151
|
-
- `retry: RetryConfig`
|
|
152
|
-
- `
|
|
150
|
+
- `namespace: str = "rq"`
|
|
151
|
+
- `retry: RetryConfig`
|
|
152
|
+
- `deduplication: DeduplicationConfig`
|
|
153
|
+
- `monitoring: MonitoringHook`
|
|
153
154
|
- `serializer: Serializer`
|
|
154
155
|
- `visibility_timeout_seconds: float = 300.0`
|
|
155
156
|
- `consumer_group: str = "redqueue"`
|
|
@@ -165,9 +166,44 @@ Retry policy for failed messages.
|
|
|
165
166
|
- `max_retries: int = 3`
|
|
166
167
|
- `base_delay_seconds: float = 0.0`
|
|
167
168
|
- `max_delay_seconds: float | None = None`
|
|
168
|
-
- `next_delay(attempts: int) -> float`
|
|
169
|
-
|
|
170
|
-
### `
|
|
169
|
+
- `next_delay(attempts: int) -> float`
|
|
170
|
+
|
|
171
|
+
### `DeduplicationConfig`
|
|
172
|
+
|
|
173
|
+
Opt-in publish-time deduplication window.
|
|
174
|
+
|
|
175
|
+
可选的发布时去重窗口配置。
|
|
176
|
+
|
|
177
|
+
- `enabled: bool = False`
|
|
178
|
+
- `ttl_seconds: float = 86400.0`
|
|
179
|
+
|
|
180
|
+
When enabled, callers may pass `dedup_key` to `publish()` or `delay()`. RedQueue
|
|
181
|
+
stores the first message id in Redis with `SET NX` and the configured TTL.
|
|
182
|
+
Duplicate calls with the same key return the stored message id and do not
|
|
183
|
+
enqueue or schedule another message. Deduplication keys are not deleted on
|
|
184
|
+
`ack()`; the TTL controls the deduplication window.
|
|
185
|
+
|
|
186
|
+
启用后,调用方可以在 `publish()` 或 `delay()` 中传入 `dedup_key`。RedQueue
|
|
187
|
+
会用 Redis `SET NX` 和配置的 TTL 存储第一次消息 ID。相同 key 的重复调用会
|
|
188
|
+
返回已存储的消息 ID,不会再次入队或调度。去重 key 不会在 `ack()` 时删除;
|
|
189
|
+
TTL 控制去重窗口。
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from redqueue import DeduplicationConfig, QueueClient
|
|
193
|
+
|
|
194
|
+
client = QueueClient.from_url(
|
|
195
|
+
"redis://127.0.0.1:6379/0",
|
|
196
|
+
queue="emails",
|
|
197
|
+
deduplication=DeduplicationConfig(enabled=True, ttl_seconds=3600),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
first_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
201
|
+
second_id = client.publish({"order": 1}, dedup_key="order-1")
|
|
202
|
+
|
|
203
|
+
assert second_id == first_id
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `BackendType`
|
|
171
207
|
|
|
172
208
|
Supported backends.
|
|
173
209
|
|
|
@@ -309,9 +345,10 @@ All RedQueue custom exceptions inherit from `RedQueueError`.
|
|
|
309
345
|
- `message.consumed`
|
|
310
346
|
- `message.acked`
|
|
311
347
|
- `message.nacked`
|
|
312
|
-
- `message.retried`
|
|
313
|
-
- `message.dead_lettered`
|
|
314
|
-
- `
|
|
348
|
+
- `message.retried`
|
|
349
|
+
- `message.dead_lettered`
|
|
350
|
+
- `message.deduplicated`
|
|
351
|
+
- `delay.scheduled`
|
|
315
352
|
- `delay.released`
|
|
316
353
|
- `backend.error`
|
|
317
354
|
|
|
@@ -345,10 +382,10 @@ Streams are rejected with `RedisCompatibilityError` when Redis is below `5.0`.
|
|
|
345
382
|
|
|
346
383
|
## CLI / 命令行工具
|
|
347
384
|
|
|
348
|
-
RedQueue `0.
|
|
385
|
+
RedQueue `0.14.0` provides a `redqueue` console command and a
|
|
349
386
|
`python -m redqueue` module entry point for developer diagnostics.
|
|
350
387
|
|
|
351
|
-
RedQueue `0.
|
|
388
|
+
RedQueue `0.14.0` 提供 `redqueue` 控制台命令和 `python -m redqueue`
|
|
352
389
|
模块入口,用于开发者调试。
|
|
353
390
|
|
|
354
391
|
Commands / 命令:
|