redqueue 0.11.1__tar.gz → 0.12.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.11.1 → redqueue-0.12.0}/CHANGELOG.md +58 -11
- {redqueue-0.11.1 → redqueue-0.12.0}/PKG-INFO +41 -1
- {redqueue-0.11.1 → redqueue-0.12.0}/README-zh-CN.md +52 -12
- {redqueue-0.11.1 → redqueue-0.12.0}/README.md +54 -14
- {redqueue-0.11.1 → redqueue-0.12.0}/docs/API.md +48 -13
- {redqueue-0.11.1 → redqueue-0.12.0}/pyproject.toml +13 -10
- redqueue-0.12.0/src/redqueue/__main__.py +9 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/_version.py +1 -1
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/async_client.py +80 -57
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/async_list.py +22 -1
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/list.py +22 -1
- redqueue-0.12.0/src/redqueue/cli.py +533 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/client.py +53 -40
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/fakes.py +19 -16
- redqueue-0.12.0/tests/test_cli.py +332 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_project_skeleton.py +227 -133
- {redqueue-0.11.1 → redqueue-0.12.0}/.github/workflows/ci.yml +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/.gitignore +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/CODE_OF_CONDUCT.md +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/CONTRIBUTING.md +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/LICENSE +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/NOTICE +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/docs/RELEASE.md +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/README.md +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/__init__.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/async_list_queue.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/common.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/compatibility_check.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/custom_serializer.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/delayed_tasks.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/monitoring_hooks.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/stream_queue.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/examples/sync_list_queue.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/requirements.txt +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/scripts/check.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/__init__.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/__init__.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/async_delay.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/async_stream.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/base.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/delay.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/backends/stream.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/compat.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/config.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/connection.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/exceptions.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/message.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/monitoring.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/src/redqueue/serialization.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/README.md +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/__init__.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_availability.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_backend_contracts.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_integration_redis.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_performance.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_real_redis_availability.py +0 -0
- {redqueue-0.11.1 → redqueue-0.12.0}/tests/test_real_redis_performance.py +0 -0
|
@@ -7,24 +7,71 @@ 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.
|
|
10
|
+
## [0.12.0] - 2026-06-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added the `redqueue` CLI and `python -m redqueue` module entry point for
|
|
15
|
+
developer debugging.
|
|
16
|
+
- Added CLI commands for Redis compatibility checks, queue statistics, message
|
|
17
|
+
publish, consume with optional ack/nack/retry, delayed scheduling, due
|
|
18
|
+
release, and dead-letter inspection.
|
|
19
|
+
- Added deterministic JSON CLI output and user-facing JSON validation errors.
|
|
20
|
+
- Added CLI unit tests with injected fake Redis and queue clients.
|
|
11
21
|
|
|
12
22
|
### Fixed
|
|
13
23
|
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
- Normalized `BRPOPLPUSH` timeout values to integer seconds for Redis versions
|
|
25
|
+
older than 6.2, improving Redis 5.x List consume compatibility.
|
|
26
|
+
|
|
27
|
+
### 新增
|
|
28
|
+
|
|
29
|
+
- 新增 `redqueue` CLI 和 `python -m redqueue` 模块入口,方便开发者调试。
|
|
30
|
+
- 新增 Redis 兼容性检查、队列统计、消息发布、消费并可选 ack/nack/retry、
|
|
31
|
+
延迟调度、到期释放和死信查看命令。
|
|
32
|
+
- CLI 输出稳定 JSON,并提供面向用户的 JSON 参数校验错误。
|
|
33
|
+
- 新增基于 fake Redis 和 fake queue client 的 CLI 单元测试。
|
|
19
34
|
|
|
20
35
|
### 修复
|
|
21
36
|
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
- 对 Redis 6.2 以下版本使用 `BRPOPLPUSH` 时,将 timeout 规范为整数秒,
|
|
38
|
+
提升 Redis 5.x List 消费兼容性。
|
|
39
|
+
|
|
40
|
+
## [0.11.2] - 2026-06-21
|
|
26
41
|
|
|
27
|
-
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- Fixed cleanup for directly constructed sync clients when owned Redis backend
|
|
45
|
+
initialization fails.
|
|
46
|
+
- Fixed cleanup for directly constructed async clients when lazy backend
|
|
47
|
+
initialization fails.
|
|
48
|
+
- Made sync and async client `close()` idempotent for owned Redis clients.
|
|
49
|
+
|
|
50
|
+
### 修复
|
|
51
|
+
|
|
52
|
+
- 修复直接构造同步客户端时,如果 owned Redis 的后端初始化失败,Redis client
|
|
53
|
+
未释放的问题。
|
|
54
|
+
- 修复直接构造异步客户端时,如果懒加载后端初始化失败,Redis client 未释放的问题。
|
|
55
|
+
- 同步和异步客户端的 `close()` 对 owned Redis client 变为幂等。
|
|
56
|
+
|
|
57
|
+
## [0.11.1] - 2026-06-21
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- Fixed resource cleanup in sync and async `from_url()` when Redis capability
|
|
62
|
+
detection, configuration validation, or backend initialization fails after the
|
|
63
|
+
client created an owned Redis connection.
|
|
64
|
+
- Added explicit `owns_redis` override support to sync and async `from_url()`
|
|
65
|
+
for advanced ownership control.
|
|
66
|
+
|
|
67
|
+
### 修复
|
|
68
|
+
|
|
69
|
+
- 修复同步和异步 `from_url()` 在自动创建 Redis 连接后,如果 Redis 能力探测、
|
|
70
|
+
配置校验或后端初始化失败,已创建连接未释放的问题。
|
|
71
|
+
- 同步和异步 `from_url()` 新增显式 `owns_redis` 覆盖支持,用于高级资源所有权
|
|
72
|
+
控制。
|
|
73
|
+
|
|
74
|
+
## [0.11.0] - 2026-06-21
|
|
28
75
|
|
|
29
76
|
### Added
|
|
30
77
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redqueue
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Redis-backed Python message queue library with List, Streams, delayed tasks, 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
|
|
@@ -50,6 +50,7 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
50
50
|
- Delayed tasks based on Redis Sorted Set.
|
|
51
51
|
- Sync client `QueueClient` and async client `AsyncQueueClient`.
|
|
52
52
|
- Redis connection pool managers for shared sync and async resources.
|
|
53
|
+
- `redqueue` CLI for local debugging and operational checks.
|
|
53
54
|
- Unified exception hierarchy with structured context.
|
|
54
55
|
- Monitoring events for publish, consume, ack, nack, retry, dead letter, delay,
|
|
55
56
|
and backend errors.
|
|
@@ -80,12 +81,51 @@ Redis:
|
|
|
80
81
|
pip install redqueue
|
|
81
82
|
```
|
|
82
83
|
|
|
84
|
+
The package installs a `redqueue` command. You can also run it with
|
|
85
|
+
`python -m redqueue` from a source checkout.
|
|
86
|
+
|
|
83
87
|
For local development:
|
|
84
88
|
|
|
85
89
|
```bash
|
|
86
90
|
python -m pip install -r requirements.txt
|
|
87
91
|
```
|
|
88
92
|
|
|
93
|
+
## CLI
|
|
94
|
+
|
|
95
|
+
Check Redis compatibility:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
redqueue check --url redis://127.0.0.1:6379/0
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Inspect queue counts:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
redqueue stats --url redis://127.0.0.1:6379/0 --queue emails
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Publish and consume messages:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
redqueue publish --queue emails --payload '{"to":"user@example.com"}'
|
|
111
|
+
redqueue consume --queue emails --timeout 1 --ack
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Delayed task debugging:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
redqueue delay --queue emails --payload '{"to":"later@example.com"}' --delay-seconds 60
|
|
118
|
+
redqueue schedule-due --queue emails --limit 100
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Dead-letter inspection:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
redqueue dead-letters --queue emails --limit 20
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
All command output is JSON so it can be piped into scripts or log processors.
|
|
128
|
+
|
|
89
129
|
## Quick Start
|
|
90
130
|
|
|
91
131
|
Synchronous List queue:
|
|
@@ -14,9 +14,10 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
14
14
|
`BRPOPLPUSH`。
|
|
15
15
|
- 基于 Redis Streams 的消费组后端,Streams 要求 Redis `>=5.0`。
|
|
16
16
|
- 基于 Redis Sorted Set 的延迟任务。
|
|
17
|
-
- 同步客户端 `QueueClient` 与异步客户端 `AsyncQueueClient`。
|
|
18
|
-
- 支持同步和异步 Redis 连接池管理器,方便多个客户端共享连接池。
|
|
19
|
-
-
|
|
17
|
+
- 同步客户端 `QueueClient` 与异步客户端 `AsyncQueueClient`。
|
|
18
|
+
- 支持同步和异步 Redis 连接池管理器,方便多个客户端共享连接池。
|
|
19
|
+
- 提供 `redqueue` CLI,用于本地调试和运行时检查。
|
|
20
|
+
- 带结构化上下文的统一异常体系。
|
|
20
21
|
- 针对发布、消费、确认、拒绝、重试、死信、延迟和后端错误的监控事件。
|
|
21
22
|
- 通过 `INFO server` 探测 Redis 能力。
|
|
22
23
|
- Apache License 2.0。
|
|
@@ -41,17 +42,56 @@ Redis:
|
|
|
41
42
|
|
|
42
43
|
## 安装
|
|
43
44
|
|
|
44
|
-
```bash
|
|
45
|
-
pip install redqueue
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
```bash
|
|
46
|
+
pip install redqueue
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
安装后会提供 `redqueue` 命令。从源码目录调试时也可以使用
|
|
50
|
+
`python -m redqueue`。
|
|
51
|
+
|
|
52
|
+
本地开发:
|
|
49
53
|
|
|
50
54
|
```bash
|
|
51
|
-
python -m pip install -r requirements.txt
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
##
|
|
55
|
+
python -m pip install -r requirements.txt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## CLI
|
|
59
|
+
|
|
60
|
+
检查 Redis 兼容性:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
redqueue check --url redis://127.0.0.1:6379/0
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
查看队列统计:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
redqueue stats --url redis://127.0.0.1:6379/0 --queue emails
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
发布和消费消息:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
redqueue publish --queue emails --payload '{"to":"user@example.com"}'
|
|
76
|
+
redqueue consume --queue emails --timeout 1 --ack
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
调试延迟任务:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
redqueue delay --queue emails --payload '{"to":"later@example.com"}' --delay-seconds 60
|
|
83
|
+
redqueue schedule-due --queue emails --limit 100
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
查看死信:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
redqueue dead-letters --queue emails --limit 20
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
所有命令都输出 JSON,方便接入脚本和日志处理流程。
|
|
93
|
+
|
|
94
|
+
## 快速开始
|
|
55
95
|
|
|
56
96
|
同步 List 队列:
|
|
57
97
|
|
|
@@ -15,9 +15,10 @@ https://github.com/SpringMirror-pear/redqueue.git
|
|
|
15
15
|
fallback on older compatible Redis versions.
|
|
16
16
|
- Redis Streams backend with consumer groups. Streams require Redis `>=5.0`.
|
|
17
17
|
- Delayed tasks based on Redis Sorted Set.
|
|
18
|
-
- Sync client `QueueClient` and async client `AsyncQueueClient`.
|
|
19
|
-
- Redis connection pool managers for shared sync and async resources.
|
|
20
|
-
-
|
|
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
|
+
- Unified exception hierarchy with structured context.
|
|
21
22
|
- Monitoring events for publish, consume, ack, nack, retry, dead letter, delay,
|
|
22
23
|
and backend errors.
|
|
23
24
|
- Redis capability detection from `INFO server`.
|
|
@@ -43,17 +44,56 @@ Redis:
|
|
|
43
44
|
|
|
44
45
|
## Installation
|
|
45
46
|
|
|
46
|
-
```bash
|
|
47
|
-
pip install redqueue
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
```bash
|
|
48
|
+
pip install redqueue
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The package installs a `redqueue` command. You can also run it with
|
|
52
|
+
`python -m redqueue` from a source checkout.
|
|
53
|
+
|
|
54
|
+
For local development:
|
|
51
55
|
|
|
52
56
|
```bash
|
|
53
|
-
python -m pip install -r requirements.txt
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
##
|
|
57
|
+
python -m pip install -r requirements.txt
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## CLI
|
|
61
|
+
|
|
62
|
+
Check Redis compatibility:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
redqueue check --url redis://127.0.0.1:6379/0
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Inspect queue counts:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
redqueue stats --url redis://127.0.0.1:6379/0 --queue emails
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Publish and consume messages:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
redqueue publish --queue emails --payload '{"to":"user@example.com"}'
|
|
78
|
+
redqueue consume --queue emails --timeout 1 --ack
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Delayed task debugging:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
redqueue delay --queue emails --payload '{"to":"later@example.com"}' --delay-seconds 60
|
|
85
|
+
redqueue schedule-due --queue emails --limit 100
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Dead-letter inspection:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
redqueue dead-letters --queue emails --limit 20
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
All command output is JSON so it can be piped into scripts or log processors.
|
|
95
|
+
|
|
96
|
+
## Quick Start
|
|
57
97
|
|
|
58
98
|
Synchronous List queue:
|
|
59
99
|
|
|
@@ -195,7 +235,7 @@ RedQueue uses a lightweight Git Flow model:
|
|
|
195
235
|
## Documentation
|
|
196
236
|
|
|
197
237
|
- Chinese README: [README-zh-CN.md](README-zh-CN.md)
|
|
198
|
-
- API: [docs/API.md](docs/API.md)
|
|
238
|
+
- API: [docs/API.md](docs/API.md)
|
|
199
239
|
- Examples: [examples/README.md](examples/README.md)
|
|
200
240
|
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
201
241
|
- Release process: [docs/RELEASE.md](docs/RELEASE.md)
|
|
@@ -205,7 +245,7 @@ RedQueue uses a lightweight Git Flow model:
|
|
|
205
245
|
|
|
206
246
|
## Examples
|
|
207
247
|
|
|
208
|
-
The `examples/` directory contains runnable scripts for synchronous List queues,
|
|
248
|
+
The `examples/` directory contains runnable scripts for synchronous List queues,
|
|
209
249
|
asynchronous List queues, Streams, delayed tasks, monitoring hooks, custom
|
|
210
250
|
serializers, and Redis compatibility checks.
|
|
211
251
|
|
|
@@ -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.12.0`.
|
|
4
4
|
|
|
5
|
-
本文档描述 RedQueue `0.
|
|
5
|
+
本文档描述 RedQueue `0.12.0` 的公开 API。
|
|
6
6
|
|
|
7
7
|
## Clients / 客户端
|
|
8
8
|
|
|
@@ -25,6 +25,8 @@ client = QueueClient.from_url(
|
|
|
25
25
|
Methods / 方法:
|
|
26
26
|
|
|
27
27
|
- `from_url(url, *, queue, backend="list", connection_manager=None, **options) -> QueueClient`
|
|
28
|
+
- Advanced options include `pool_options`, injected `redis`, injected
|
|
29
|
+
`capabilities`, and `owns_redis`.
|
|
28
30
|
- `publish(payload, *, delay=None, headers=None, message_id=None) -> str`
|
|
29
31
|
- `consume(*, timeout=None, batch_size=1) -> Message | list[Message] | None`
|
|
30
32
|
- `ack(message) -> None`
|
|
@@ -57,6 +59,8 @@ client = await AsyncQueueClient.from_url(
|
|
|
57
59
|
Methods / 方法:
|
|
58
60
|
|
|
59
61
|
- `await from_url(url, *, queue, backend="list", connection_manager=None, **options) -> AsyncQueueClient`
|
|
62
|
+
- Advanced options include `pool_options`, injected `redis`, injected
|
|
63
|
+
`capabilities`, and `owns_redis`.
|
|
60
64
|
- `await publish(payload, *, delay=None, headers=None, message_id=None) -> str`
|
|
61
65
|
- `await consume(*, timeout=None, batch_size=1) -> Message | list[Message] | None`
|
|
62
66
|
- `await ack(message) -> None`
|
|
@@ -299,14 +303,45 @@ Monitoring events do not include business payload by default.
|
|
|
299
303
|
|
|
300
304
|
监控事件默认不包含业务 payload。
|
|
301
305
|
|
|
302
|
-
## Redis Capability Detection / Redis 能力探测
|
|
303
|
-
|
|
304
|
-
- `RedisVersion`
|
|
305
|
-
- `RedisCapabilities`
|
|
306
|
-
- `extract_redis_version(info)`
|
|
307
|
-
- `detect_capabilities(client)`
|
|
308
|
-
- `detect_capabilities_async(client)`
|
|
309
|
-
|
|
310
|
-
Streams are rejected with `RedisCompatibilityError` when Redis is below `5.0`.
|
|
311
|
-
|
|
312
|
-
当 Redis 低于 `5.0` 时,启用 Streams 会抛出 `RedisCompatibilityError`。
|
|
306
|
+
## Redis Capability Detection / Redis 能力探测
|
|
307
|
+
|
|
308
|
+
- `RedisVersion`
|
|
309
|
+
- `RedisCapabilities`
|
|
310
|
+
- `extract_redis_version(info)`
|
|
311
|
+
- `detect_capabilities(client)`
|
|
312
|
+
- `detect_capabilities_async(client)`
|
|
313
|
+
|
|
314
|
+
Streams are rejected with `RedisCompatibilityError` when Redis is below `5.0`.
|
|
315
|
+
|
|
316
|
+
当 Redis 低于 `5.0` 时,启用 Streams 会抛出 `RedisCompatibilityError`。
|
|
317
|
+
|
|
318
|
+
## CLI / 命令行工具
|
|
319
|
+
|
|
320
|
+
RedQueue `0.12.0` provides a `redqueue` console command and a
|
|
321
|
+
`python -m redqueue` module entry point for developer diagnostics.
|
|
322
|
+
|
|
323
|
+
RedQueue `0.12.0` 提供 `redqueue` 控制台命令和 `python -m redqueue`
|
|
324
|
+
模块入口,用于开发者调试。
|
|
325
|
+
|
|
326
|
+
Commands / 命令:
|
|
327
|
+
|
|
328
|
+
- `redqueue check --url redis://127.0.0.1:6379/0`
|
|
329
|
+
- `redqueue stats --queue emails [--backend list|stream]`
|
|
330
|
+
- `redqueue publish --queue emails --payload '{"to":"user@example.com"}'`
|
|
331
|
+
- `redqueue consume --queue emails [--ack|--nack|--retry]`
|
|
332
|
+
- `redqueue delay --queue emails --payload '{"to":"later@example.com"}' --delay-seconds 60`
|
|
333
|
+
- `redqueue schedule-due --queue emails --limit 100`
|
|
334
|
+
- `redqueue dead-letters --queue emails --limit 20`
|
|
335
|
+
|
|
336
|
+
Common options / 通用选项:
|
|
337
|
+
|
|
338
|
+
- `--url`: Redis URL. Defaults to `redis://127.0.0.1:6379/0`.
|
|
339
|
+
- `--queue`: RedQueue queue name.
|
|
340
|
+
- `--backend`: `list` or `stream`.
|
|
341
|
+
- `--namespace`: Redis key namespace. Defaults to `rq`.
|
|
342
|
+
- `--consumer-group`: Streams consumer group. Defaults to `redqueue`.
|
|
343
|
+
- `--consumer-name`: Optional Streams consumer name.
|
|
344
|
+
|
|
345
|
+
Payload and headers are JSON strings. Command responses are stable JSON objects.
|
|
346
|
+
|
|
347
|
+
Payload 和 headers 使用 JSON 字符串。命令响应为稳定 JSON 对象。
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
requires = ["hatchling==1.30.1"]
|
|
3
3
|
build-backend = "hatchling.build"
|
|
4
4
|
|
|
5
|
-
[project]
|
|
6
|
-
name = "redqueue"
|
|
7
|
-
version = "0.
|
|
5
|
+
[project]
|
|
6
|
+
name = "redqueue"
|
|
7
|
+
version = "0.12.0"
|
|
8
8
|
description = "Redis-backed Python message queue library with List, Streams, delayed tasks, and monitoring."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -33,13 +33,16 @@ dependencies = [
|
|
|
33
33
|
"redis==6.4.0",
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
-
[project.urls]
|
|
37
|
-
Homepage = "https://github.com/SpringMirror-pear/redqueue"
|
|
38
|
-
Repository = "https://github.com/SpringMirror-pear/redqueue.git"
|
|
39
|
-
Issues = "https://github.com/SpringMirror-pear/redqueue/issues"
|
|
40
|
-
|
|
41
|
-
[project.
|
|
42
|
-
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/SpringMirror-pear/redqueue"
|
|
38
|
+
Repository = "https://github.com/SpringMirror-pear/redqueue.git"
|
|
39
|
+
Issues = "https://github.com/SpringMirror-pear/redqueue/issues"
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
redqueue = "redqueue.cli:main"
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = [
|
|
43
46
|
"pytest==9.1.1; python_version >= '3.10'",
|
|
44
47
|
"pytest-asyncio==1.4.0; python_version >= '3.10'",
|
|
45
48
|
"ruff==0.15.18",
|
|
@@ -59,6 +59,7 @@ class AsyncQueueClient:
|
|
|
59
59
|
self.redis = redis
|
|
60
60
|
self.capabilities = capabilities
|
|
61
61
|
self._owns_redis = owns_redis
|
|
62
|
+
self._closed = False
|
|
62
63
|
self.backend: AsyncListBackend | AsyncStreamBackend | None = None
|
|
63
64
|
self.delay_backend: AsyncDelayBackend | None = None
|
|
64
65
|
self.config.monitoring.emit(
|
|
@@ -88,7 +89,8 @@ class AsyncQueueClient:
|
|
|
88
89
|
connection_manager: Optional async connection manager used to create
|
|
89
90
|
a client from a shared pool.
|
|
90
91
|
**options: Additional ``QueueConfig`` options. Tests may also pass
|
|
91
|
-
``redis``, ``capabilities``,
|
|
92
|
+
``redis``, ``capabilities``, ``pool_options``, or
|
|
93
|
+
``owns_redis``.
|
|
92
94
|
|
|
93
95
|
Returns:
|
|
94
96
|
An initialized ``AsyncQueueClient`` with its primary backend ready.
|
|
@@ -99,50 +101,48 @@ class AsyncQueueClient:
|
|
|
99
101
|
QueueConfigError: If configuration values are invalid.
|
|
100
102
|
"""
|
|
101
103
|
|
|
102
|
-
redis = options.pop("redis", None)
|
|
103
|
-
pool_options = options.pop("pool_options", None) or {}
|
|
104
|
-
explicit_owns_redis = options.pop("owns_redis", None)
|
|
105
|
-
owns_redis = (
|
|
106
|
-
bool(explicit_owns_redis)
|
|
107
|
-
if explicit_owns_redis is not None
|
|
108
|
-
else False
|
|
109
|
-
)
|
|
110
|
-
if redis is None:
|
|
111
|
-
if connection_manager is not None:
|
|
112
|
-
redis = connection_manager.redis()
|
|
113
|
-
else:
|
|
114
|
-
redis = Redis.from_url(url, **pool_options)
|
|
115
|
-
owns_redis = (
|
|
116
|
-
True
|
|
117
|
-
if explicit_owns_redis is None
|
|
118
|
-
else bool(explicit_owns_redis)
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
await result
|
|
145
|
-
raise
|
|
104
|
+
redis = options.pop("redis", None)
|
|
105
|
+
pool_options = options.pop("pool_options", None) or {}
|
|
106
|
+
explicit_owns_redis = options.pop("owns_redis", None)
|
|
107
|
+
owns_redis = (
|
|
108
|
+
bool(explicit_owns_redis)
|
|
109
|
+
if explicit_owns_redis is not None
|
|
110
|
+
else False
|
|
111
|
+
)
|
|
112
|
+
if redis is None:
|
|
113
|
+
if connection_manager is not None:
|
|
114
|
+
redis = connection_manager.redis()
|
|
115
|
+
else:
|
|
116
|
+
redis = Redis.from_url(url, **pool_options)
|
|
117
|
+
owns_redis = (
|
|
118
|
+
True
|
|
119
|
+
if explicit_owns_redis is None
|
|
120
|
+
else bool(explicit_owns_redis)
|
|
121
|
+
)
|
|
122
|
+
capabilities = options.pop("capabilities", None)
|
|
123
|
+
if capabilities is None:
|
|
124
|
+
try:
|
|
125
|
+
capabilities = await detect_capabilities_async(
|
|
126
|
+
cast(AsyncRedisInfoClient, redis)
|
|
127
|
+
)
|
|
128
|
+
except Exception:
|
|
129
|
+
if owns_redis:
|
|
130
|
+
await cls._close_redis(redis)
|
|
131
|
+
raise
|
|
132
|
+
try:
|
|
133
|
+
config = QueueConfig(queue=queue, backend=backend, **options)
|
|
134
|
+
except Exception:
|
|
135
|
+
if owns_redis:
|
|
136
|
+
await cls._close_redis(redis)
|
|
137
|
+
raise
|
|
138
|
+
client = cls(
|
|
139
|
+
config=config,
|
|
140
|
+
redis=redis,
|
|
141
|
+
capabilities=capabilities,
|
|
142
|
+
owns_redis=owns_redis,
|
|
143
|
+
)
|
|
144
|
+
await client._ensure_backend()
|
|
145
|
+
return client
|
|
146
146
|
|
|
147
147
|
async def publish(
|
|
148
148
|
self,
|
|
@@ -324,7 +324,7 @@ class AsyncQueueClient:
|
|
|
324
324
|
async def close(self) -> None:
|
|
325
325
|
"""Close the async Redis client when this client owns it."""
|
|
326
326
|
|
|
327
|
-
if not self._owns_redis:
|
|
327
|
+
if self._closed or not self._owns_redis:
|
|
328
328
|
return
|
|
329
329
|
|
|
330
330
|
close = getattr(self.redis, "aclose", None) or getattr(
|
|
@@ -333,9 +333,8 @@ class AsyncQueueClient:
|
|
|
333
333
|
None,
|
|
334
334
|
)
|
|
335
335
|
if close is not None:
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
await result
|
|
336
|
+
await self._call_close(close)
|
|
337
|
+
self._closed = True
|
|
339
338
|
|
|
340
339
|
async def __aenter__(self) -> AsyncQueueClient:
|
|
341
340
|
"""Enter an asynchronous resource-management context."""
|
|
@@ -371,24 +370,48 @@ class AsyncQueueClient:
|
|
|
371
370
|
capabilities = self.capabilities
|
|
372
371
|
if capabilities is None:
|
|
373
372
|
raise TypeError("Redis capabilities are required before backend use")
|
|
374
|
-
|
|
375
|
-
|
|
373
|
+
try:
|
|
374
|
+
self.backend = AsyncListBackend(self.redis, self.config, capabilities)
|
|
375
|
+
return self.backend
|
|
376
|
+
except Exception:
|
|
377
|
+
await self.close()
|
|
378
|
+
raise
|
|
376
379
|
if self.config.backend_type is BackendType.STREAM:
|
|
377
380
|
if self.redis is None:
|
|
378
381
|
raise TypeError("redis client is required for async Streams backend")
|
|
379
382
|
capabilities = self.capabilities
|
|
380
383
|
if capabilities is None:
|
|
381
384
|
raise TypeError("Redis capabilities are required before backend use")
|
|
382
|
-
|
|
383
|
-
self.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
try:
|
|
386
|
+
self.backend = await AsyncStreamBackend.create(
|
|
387
|
+
self.redis,
|
|
388
|
+
self.config,
|
|
389
|
+
capabilities,
|
|
390
|
+
)
|
|
391
|
+
return self.backend
|
|
392
|
+
except Exception:
|
|
393
|
+
await self.close()
|
|
394
|
+
raise
|
|
388
395
|
raise NotImplementedError(
|
|
389
396
|
f"backend {self.config.backend_type.value!r} is not implemented"
|
|
390
397
|
)
|
|
391
398
|
|
|
399
|
+
@staticmethod
|
|
400
|
+
async def _close_redis(redis: Any) -> None:
|
|
401
|
+
"""Close an async Redis-like object if it exposes a close method."""
|
|
402
|
+
|
|
403
|
+
close = getattr(redis, "aclose", None) or getattr(redis, "close", None)
|
|
404
|
+
if close is not None:
|
|
405
|
+
await AsyncQueueClient._call_close(close)
|
|
406
|
+
|
|
407
|
+
@staticmethod
|
|
408
|
+
async def _call_close(close: Any) -> None:
|
|
409
|
+
"""Call a sync or async close method."""
|
|
410
|
+
|
|
411
|
+
result = close()
|
|
412
|
+
if hasattr(result, "__await__"):
|
|
413
|
+
await result
|
|
414
|
+
|
|
392
415
|
async def _ensure_delay_backend(self) -> AsyncDelayBackend:
|
|
393
416
|
"""Return the initialized async delay scheduler, creating it when needed."""
|
|
394
417
|
|