DefStream-RabbitMQ 0.1.1.2__py3-none-any.whl → 0.1.2.6__py3-none-any.whl
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.
Potentially problematic release.
This version of DefStream-RabbitMQ might be problematic. Click here for more details.
- DefStream/Broker/Implements/RabbitMQ/Configuration.py +1 -1
- DefStream/Broker/Implements/RabbitMQ/Connection.py +42 -10
- DefStream/Broker/Implements/RabbitMQ/Consumer.py +3 -5
- DefStream/Broker/Implements/RabbitMQ/Event.py +1 -1
- DefStream/Broker/Implements/RabbitMQ/Exchange.py +8 -3
- DefStream/Broker/Implements/RabbitMQ/Policies.py +1 -1
- DefStream/Broker/Implements/RabbitMQ/Queue.py +15 -3
- DefStream/Broker/Implements/RabbitMQ/Stream.py +1 -1
- DefStream/Broker/Implements/RabbitMQ/Subscription.py +27 -0
- defstream_rabbitmq-0.1.2.6.dist-info/METADATA +281 -0
- defstream_rabbitmq-0.1.2.6.dist-info/RECORD +16 -0
- defstream_rabbitmq-0.1.1.2.dist-info/METADATA +0 -191
- defstream_rabbitmq-0.1.1.2.dist-info/RECORD +0 -16
- {defstream_rabbitmq-0.1.1.2.dist-info → defstream_rabbitmq-0.1.2.6.dist-info}/WHEEL +0 -0
- {defstream_rabbitmq-0.1.1.2.dist-info → defstream_rabbitmq-0.1.2.6.dist-info}/licenses/LICENSE +0 -0
- {defstream_rabbitmq-0.1.1.2.dist-info → defstream_rabbitmq-0.1.2.6.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from DefStream.Broker import (
|
|
4
4
|
Connection as BaseConnection,
|
|
5
5
|
GetExchange,
|
|
6
6
|
GetQueue,
|
|
@@ -9,6 +9,8 @@ from ...Connection import (
|
|
|
9
9
|
Declarable,
|
|
10
10
|
TaskSender,
|
|
11
11
|
Requestable,
|
|
12
|
+
PrioritySupport,
|
|
13
|
+
EventHandler,
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
from .Configuration import Configuration
|
|
@@ -18,7 +20,6 @@ from .Queue import Queue
|
|
|
18
20
|
from .Stream import Stream
|
|
19
21
|
from .Consumer import Consumer
|
|
20
22
|
from .Subscription import Subscription
|
|
21
|
-
from ...Event import EventHandler
|
|
22
23
|
|
|
23
24
|
from pika import (
|
|
24
25
|
BlockingConnection,
|
|
@@ -37,7 +38,7 @@ from enum import Enum
|
|
|
37
38
|
from uuid import uuid4
|
|
38
39
|
|
|
39
40
|
from typing import (
|
|
40
|
-
Any,
|
|
41
|
+
Any as AnyValue,
|
|
41
42
|
Iterator,
|
|
42
43
|
Union,
|
|
43
44
|
Optional,
|
|
@@ -75,7 +76,10 @@ class Parameters(Mapping):
|
|
|
75
76
|
def __len__(self) -> int:
|
|
76
77
|
return self.args.__len__()
|
|
77
78
|
|
|
78
|
-
def __getitem__(
|
|
79
|
+
def __getitem__(
|
|
80
|
+
self,
|
|
81
|
+
key: AnyValue,
|
|
82
|
+
) -> AnyValue:
|
|
79
83
|
return self.args.__getitem__(key)
|
|
80
84
|
|
|
81
85
|
def __contains__(self, key: object) -> bool:
|
|
@@ -106,6 +110,7 @@ class Connection(
|
|
|
106
110
|
Declarable,
|
|
107
111
|
TaskSender,
|
|
108
112
|
Requestable,
|
|
113
|
+
PrioritySupport,
|
|
109
114
|
):
|
|
110
115
|
"""Connection of Event Broker for RabbitMQ"""
|
|
111
116
|
def __init__(self, conf: Configuration):
|
|
@@ -140,7 +145,7 @@ class Connection(
|
|
|
140
145
|
|
|
141
146
|
def declare(
|
|
142
147
|
self,
|
|
143
|
-
parameters:
|
|
148
|
+
parameters: AnyValue,
|
|
144
149
|
) -> None:
|
|
145
150
|
subscription = Subscription.parse(parameters)
|
|
146
151
|
channel = self.connected().channel()
|
|
@@ -155,6 +160,8 @@ class Connection(
|
|
|
155
160
|
'x-dead-letter-exchange': '',
|
|
156
161
|
'x-dead-letter-routing-key': subscription.error,
|
|
157
162
|
}
|
|
163
|
+
if subscription.max_priority is not None:
|
|
164
|
+
arguments['x-max-priority'] = subscription.max_priority
|
|
158
165
|
channel.queue_declare(
|
|
159
166
|
subscription.queue,
|
|
160
167
|
durable=True,
|
|
@@ -163,13 +170,26 @@ class Connection(
|
|
|
163
170
|
finally:
|
|
164
171
|
if channel.is_open:
|
|
165
172
|
channel.close()
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
def priority_parameters(
|
|
176
|
+
self,
|
|
177
|
+
parameters: AnyValue,
|
|
178
|
+
) -> Subscription:
|
|
179
|
+
"""작업 기본값을 검증하고 선언·발행에 사용할 구독 설정을 반환한다."""
|
|
180
|
+
return Subscription.parse(parameters)
|
|
166
181
|
|
|
167
182
|
def send(
|
|
168
183
|
self,
|
|
169
|
-
body:
|
|
170
|
-
parameters:
|
|
184
|
+
body: AnyValue,
|
|
185
|
+
parameters: AnyValue,
|
|
186
|
+
*,
|
|
187
|
+
priority: Optional[int] = None,
|
|
171
188
|
) -> str:
|
|
172
189
|
subscription = Subscription.parse(parameters)
|
|
190
|
+
if priority is None:
|
|
191
|
+
priority = subscription.priority
|
|
192
|
+
subscription.validate_priority(priority)
|
|
173
193
|
connection = self.connected()
|
|
174
194
|
channel = self.publisher
|
|
175
195
|
if channel is None or not channel.is_open:
|
|
@@ -192,6 +212,7 @@ class Connection(
|
|
|
192
212
|
content_type=self.conf.encode.format,
|
|
193
213
|
content_encoding=self.conf.encode.charset,
|
|
194
214
|
delivery_mode=2,
|
|
215
|
+
priority=priority,
|
|
195
216
|
),
|
|
196
217
|
mandatory=True,
|
|
197
218
|
)
|
|
@@ -199,14 +220,25 @@ class Connection(
|
|
|
199
220
|
|
|
200
221
|
def request(
|
|
201
222
|
self,
|
|
202
|
-
body:
|
|
203
|
-
parameters:
|
|
223
|
+
body: AnyValue,
|
|
224
|
+
parameters: AnyValue,
|
|
204
225
|
timeout: float = 5,
|
|
205
|
-
|
|
226
|
+
*,
|
|
227
|
+
priority: Optional[int] = None,
|
|
228
|
+
) -> AnyValue:
|
|
206
229
|
subscription = Subscription.parse(parameters)
|
|
230
|
+
if priority is None:
|
|
231
|
+
priority = subscription.priority
|
|
232
|
+
subscription.validate_priority(priority)
|
|
207
233
|
self.connected()
|
|
208
234
|
queue = self.queue(subscription.queue)
|
|
209
235
|
try:
|
|
236
|
+
if priority is not None:
|
|
237
|
+
return queue.call(
|
|
238
|
+
body,
|
|
239
|
+
timeout=timeout,
|
|
240
|
+
priority=priority,
|
|
241
|
+
)
|
|
210
242
|
return queue.call(
|
|
211
243
|
body,
|
|
212
244
|
timeout=timeout,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from DefStream.Broker import (
|
|
4
4
|
Consumer as BaseConsumer,
|
|
5
5
|
EventHandler,
|
|
6
|
+
Event as BaseEvent,
|
|
7
|
+
EventError,
|
|
6
8
|
)
|
|
7
9
|
|
|
8
10
|
from .Serializer import (
|
|
@@ -15,10 +17,6 @@ from logging import getLogger
|
|
|
15
17
|
from .Event import Event
|
|
16
18
|
from .Policies import Requeue
|
|
17
19
|
from .Subscription import Subscription
|
|
18
|
-
from ...Event import (
|
|
19
|
-
Event as BaseEvent,
|
|
20
|
-
EventError,
|
|
21
|
-
)
|
|
22
20
|
from typing import (
|
|
23
21
|
Any,
|
|
24
22
|
Callable,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from DefStream.Broker import (
|
|
4
4
|
Sendable,
|
|
5
5
|
Callable,
|
|
6
|
+
RemoteError,
|
|
7
|
+
validate_priority,
|
|
6
8
|
)
|
|
7
9
|
|
|
8
10
|
from .Serializer import (
|
|
9
11
|
Encoder,
|
|
10
12
|
Decoder,
|
|
11
13
|
)
|
|
12
|
-
from ...Errors import RemoteError
|
|
13
14
|
from copy import deepcopy
|
|
14
15
|
from math import (
|
|
15
16
|
ceil,
|
|
@@ -74,12 +75,16 @@ class Exchange(
|
|
|
74
75
|
body,
|
|
75
76
|
event: str = None,
|
|
76
77
|
headers: Dict = {},
|
|
77
|
-
priority: int = None,
|
|
78
|
+
priority: Optional[int] = None,
|
|
78
79
|
expiration: int = None,
|
|
79
80
|
timestamp: int = None,
|
|
80
81
|
persistent: bool = True,
|
|
81
82
|
id: str = None,
|
|
82
83
|
):
|
|
84
|
+
validate_priority(
|
|
85
|
+
priority,
|
|
86
|
+
255,
|
|
87
|
+
)
|
|
83
88
|
if not timestamp: timestamp = int(time())
|
|
84
89
|
if not id: id = uuid4().hex
|
|
85
90
|
properties = BasicProperties(
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from DefStream.Broker import (
|
|
4
4
|
Sendable,
|
|
5
5
|
Callable,
|
|
6
6
|
Poppable,
|
|
7
|
+
RemoteError,
|
|
8
|
+
validate_priority,
|
|
7
9
|
)
|
|
8
10
|
|
|
9
11
|
from .Serializer import (
|
|
@@ -11,7 +13,6 @@ from .Serializer import (
|
|
|
11
13
|
Decoder,
|
|
12
14
|
)
|
|
13
15
|
from .Event import Event
|
|
14
|
-
from ...Errors import RemoteError
|
|
15
16
|
from copy import deepcopy
|
|
16
17
|
from math import (
|
|
17
18
|
ceil,
|
|
@@ -78,7 +79,7 @@ class Queue(
|
|
|
78
79
|
body,
|
|
79
80
|
event: str = None,
|
|
80
81
|
headers: Dict = {},
|
|
81
|
-
priority: int = None,
|
|
82
|
+
priority: Optional[int] = None,
|
|
82
83
|
expiration: int = None,
|
|
83
84
|
timestamp: int = None,
|
|
84
85
|
persistent: bool = True,
|
|
@@ -86,6 +87,10 @@ class Queue(
|
|
|
86
87
|
reply_to: str = None,
|
|
87
88
|
correlation_id: str = None,
|
|
88
89
|
):
|
|
90
|
+
validate_priority(
|
|
91
|
+
priority,
|
|
92
|
+
255,
|
|
93
|
+
)
|
|
89
94
|
if not timestamp: timestamp = int(time())
|
|
90
95
|
if not id: id = uuid4().hex
|
|
91
96
|
properties = BasicProperties(
|
|
@@ -113,7 +118,13 @@ class Queue(
|
|
|
113
118
|
self,
|
|
114
119
|
body: Any,
|
|
115
120
|
timeout: float = 5,
|
|
121
|
+
*,
|
|
122
|
+
priority: Optional[int] = None,
|
|
116
123
|
) -> Any:
|
|
124
|
+
validate_priority(
|
|
125
|
+
priority,
|
|
126
|
+
255,
|
|
127
|
+
)
|
|
117
128
|
if self.rpc_parameters is None:
|
|
118
129
|
raise RuntimeError('RPC requires connection parameters; obtain the queue through Connection.queue')
|
|
119
130
|
if isinstance(
|
|
@@ -173,6 +184,7 @@ class Queue(
|
|
|
173
184
|
routing_key=self.queue,
|
|
174
185
|
body=self.encode(body),
|
|
175
186
|
properties=BasicProperties(
|
|
187
|
+
priority=priority,
|
|
176
188
|
reply_to=reply_queue,
|
|
177
189
|
correlation_id=correlation_id,
|
|
178
190
|
content_type=self.encode.format,
|
|
@@ -4,6 +4,7 @@ from typing import (
|
|
|
4
4
|
Any,
|
|
5
5
|
Optional,
|
|
6
6
|
)
|
|
7
|
+
from DefStream.Broker import validate_priority
|
|
7
8
|
|
|
8
9
|
__all__ = (
|
|
9
10
|
'Subscription',
|
|
@@ -16,8 +17,23 @@ class Subscription:
|
|
|
16
17
|
offset: Optional[int] = None
|
|
17
18
|
qos: Optional[int] = None
|
|
18
19
|
error: Optional[str] = None
|
|
20
|
+
max_priority: Optional[int] = None
|
|
21
|
+
priority: Optional[int] = None
|
|
19
22
|
|
|
20
23
|
def __post_init__(self):
|
|
24
|
+
if self.priority is not None and self.max_priority is None:
|
|
25
|
+
object.__setattr__(
|
|
26
|
+
self,
|
|
27
|
+
'max_priority',
|
|
28
|
+
255,
|
|
29
|
+
)
|
|
30
|
+
validate_priority(
|
|
31
|
+
self.max_priority,
|
|
32
|
+
255,
|
|
33
|
+
minimum=1,
|
|
34
|
+
name='max_priority',
|
|
35
|
+
)
|
|
36
|
+
self.validate_priority(self.priority)
|
|
21
37
|
if not isinstance(self.queue, str) or not self.queue:
|
|
22
38
|
raise ValueError('Subscription queue must be a non-empty string')
|
|
23
39
|
if self.error is not None:
|
|
@@ -37,6 +53,17 @@ class Subscription:
|
|
|
37
53
|
int,
|
|
38
54
|
) or not 0 <= self.qos <= 65535:
|
|
39
55
|
raise ValueError('Subscription qos must be an integer between 0 and 65535')
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
def validate_priority(
|
|
59
|
+
self,
|
|
60
|
+
priority: Optional[int],
|
|
61
|
+
) -> None:
|
|
62
|
+
validate_priority(
|
|
63
|
+
priority,
|
|
64
|
+
255 if self.max_priority is None else self.max_priority,
|
|
65
|
+
)
|
|
66
|
+
return
|
|
40
67
|
|
|
41
68
|
@classmethod
|
|
42
69
|
def parse(cls, parameters: Any) -> 'Subscription':
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: DefStream-RabbitMQ
|
|
3
|
+
Version: 0.1.2.6
|
|
4
|
+
Summary: RabbitMQ broker adapter for DefStream
|
|
5
|
+
Home-page: https://github.com/yong5eon/DefStream-RabbitMQ
|
|
6
|
+
Author: Heo Yongseon
|
|
7
|
+
Project-URL: Source, https://github.com/yong5eon/DefStream-RabbitMQ
|
|
8
|
+
Project-URL: Issues, https://github.com/yong5eon/DefStream-RabbitMQ/issues
|
|
9
|
+
Project-URL: Releases, https://github.com/yong5eon/DefStream-RabbitMQ/releases
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: DefStream>=0.1.0
|
|
20
|
+
Requires-Dist: pika>=1.3.2
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: project-url
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# DefStream-RabbitMQ
|
|
33
|
+
|
|
34
|
+
**한국어** | [English](./README.en.md)
|
|
35
|
+
|
|
36
|
+
DefStream에서 RabbitMQ를 사용할 수 있게 해주는 브로커 어댑터입니다.
|
|
37
|
+
일반 큐, Exchange 라우팅, 스트림 이력 읽기, 동기 RPC를 제공하며,
|
|
38
|
+
DefStream Worker에 연결해 작업을 스레드·프로세스 풀에서 실행할 수 있습니다.
|
|
39
|
+
내부 클라이언트로 Pika를 사용합니다.
|
|
40
|
+
|
|
41
|
+
## 설치
|
|
42
|
+
|
|
43
|
+
Python **3.9 이상**과 접속 가능한 RabbitMQ 서버가 필요합니다.
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
python -m pip install DefStream-RabbitMQ
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`DefStream>=0.1.0`과 `pika>=1.3.2`도 함께 설치됩니다.
|
|
50
|
+
배포 패키지 이름은 `DefStream-RabbitMQ`이고 import 경로는
|
|
51
|
+
`DefStream.Broker.Implements.RabbitMQ`입니다.
|
|
52
|
+
|
|
53
|
+
## 큐에 보내고 받기
|
|
54
|
+
|
|
55
|
+
로컬 RabbitMQ의 `guest` 계정을 사용하는 예제입니다.
|
|
56
|
+
운영에서는 별도 계정과 환경변수·비밀 저장소를 사용하세요.
|
|
57
|
+
예제는 `defstream.example.rabbitmq` 큐를 만들며 실행 후에도 큐를 유지합니다.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
connection = Connection(Configuration(
|
|
64
|
+
host='127.0.0.1',
|
|
65
|
+
port=5672,
|
|
66
|
+
username='guest',
|
|
67
|
+
password='guest',
|
|
68
|
+
))
|
|
69
|
+
try:
|
|
70
|
+
connection.connect()
|
|
71
|
+
connection.create_queue('defstream.example.rabbitmq')
|
|
72
|
+
queue = connection.queue('defstream.example.rabbitmq')
|
|
73
|
+
queue.send({'message': 'Hello, DefStream!'})
|
|
74
|
+
event = queue.pop(timeout=1000)
|
|
75
|
+
if event is not None:
|
|
76
|
+
print(event.body)
|
|
77
|
+
event.ack()
|
|
78
|
+
finally:
|
|
79
|
+
connection.close()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
메시지는 기본 JSON 코덱으로 직렬화됩니다.
|
|
83
|
+
`pop()` 제한 시간은 **밀리초**이며, 양수 제한 시간에 메시지가 없으면 `None`을 반환합니다.
|
|
84
|
+
`None` 또는 `0`은 무기한 대기입니다.
|
|
85
|
+
처리가 성공하면 `ack()`, 재전달하려면 `nack()`, 거부하려면 `reject()`를 호출하세요.
|
|
86
|
+
거부한 메시지는 브로커의 dead-letter 설정이 있으면 해당 목적지로, 없으면 폐기됩니다.
|
|
87
|
+
|
|
88
|
+
## 연결 설정
|
|
89
|
+
|
|
90
|
+
| 옵션 | 의미 |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `host`, `port` | RabbitMQ 주소와 AMQP 포트 |
|
|
93
|
+
| `username`, `password` | 인증 정보 |
|
|
94
|
+
| `vhost` | 가상 호스트, 기본값 `/` |
|
|
95
|
+
| `ssl` | TLS 사용 여부, 기본값 `False` |
|
|
96
|
+
| `timeout` | blocked-connection 제한 시간, 밀리초 |
|
|
97
|
+
| `heartbeat` | 현재 구현은 `int(heartbeat * 2 / 1000)`초로 변환하여 Pika에 전달 |
|
|
98
|
+
| `encode`, `decode` | 메시지 코덱, 기본값 JSON |
|
|
99
|
+
|
|
100
|
+
`timeout`은 모든 작업에 대한 전체 실행 제한 시간이 아닙니다.
|
|
101
|
+
일반 연결의 heartbeat는 애플리케이션 작업·유휴 시간에 맞게 설정하고 처리되도록 관리하세요.
|
|
102
|
+
연결과 그 리소스는 **소유 스레드에서만 사용**해야 하며, 스레드·프로세스 사이에 공유하지 마세요.
|
|
103
|
+
|
|
104
|
+
## Worker로 작업 처리하기
|
|
105
|
+
|
|
106
|
+
다음은 큐와 오류 큐를 준비한 후 작업을 소비하는 실행 파일입니다.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from signal import SIGINT, signal
|
|
110
|
+
|
|
111
|
+
from DefStream.Broker.Implements.RabbitMQ import (
|
|
112
|
+
Configuration,
|
|
113
|
+
Connection,
|
|
114
|
+
Reject,
|
|
115
|
+
Subscription,
|
|
116
|
+
)
|
|
117
|
+
from DefStream.Worker import Run, ThreadPool, Worker, WorkerSetup, declare
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Add(
|
|
121
|
+
Run,
|
|
122
|
+
parameters=Subscription(
|
|
123
|
+
queue='defstream.example.rabbitmq.add',
|
|
124
|
+
qos=4,
|
|
125
|
+
error='defstream.example.rabbitmq.add.error',
|
|
126
|
+
),
|
|
127
|
+
on_error=Reject(),
|
|
128
|
+
):
|
|
129
|
+
def run(
|
|
130
|
+
self,
|
|
131
|
+
a: int,
|
|
132
|
+
b: int,
|
|
133
|
+
):
|
|
134
|
+
return a + b
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Prepare(WorkerSetup):
|
|
138
|
+
def __call__(
|
|
139
|
+
self,
|
|
140
|
+
worker: Worker,
|
|
141
|
+
) -> None:
|
|
142
|
+
for task in worker.tasks:
|
|
143
|
+
declare(
|
|
144
|
+
task=task,
|
|
145
|
+
broker=worker.broker,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == '__main__':
|
|
150
|
+
worker = Worker(
|
|
151
|
+
Connection(Configuration(
|
|
152
|
+
host='127.0.0.1',
|
|
153
|
+
port=5672,
|
|
154
|
+
username='guest',
|
|
155
|
+
password='guest',
|
|
156
|
+
)),
|
|
157
|
+
ThreadPool(4),
|
|
158
|
+
setups=Prepare(),
|
|
159
|
+
)
|
|
160
|
+
worker.add(Add)
|
|
161
|
+
signal(
|
|
162
|
+
SIGINT,
|
|
163
|
+
lambda *_: worker.stop(),
|
|
164
|
+
)
|
|
165
|
+
worker.run()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
다른 프로세스에서 같은 큐에 `{'a': 10, 'b': 20}`을 보내면 처리됩니다.
|
|
169
|
+
Worker는 실행과 완료 훅이 끝난 뒤 ACK하고, 실패하면 지정한 정책을 적용합니다.
|
|
170
|
+
`on_error`를 생략하면 기본값은 `Requeue()`입니다.
|
|
171
|
+
|
|
172
|
+
`Subscription` 옵션:
|
|
173
|
+
|
|
174
|
+
- `queue`: 작업 큐 이름.
|
|
175
|
+
- `qos`: 이 구독의 미확인 메시지 수 제한. 기본 소비자 값은 1이며, 0은 무제한입니다.
|
|
176
|
+
Worker의 공유 풀 크기와 별개입니다.
|
|
177
|
+
- `error`: `declare()`가 생성하고 연결할 오류 큐 이름. 거부된 메시지의 DLQ입니다.
|
|
178
|
+
- `offset`: RabbitMQ 스트림 구독에 사용할 정수 오프셋.
|
|
179
|
+
- `max_priority`: classic 작업 큐의 최대 우선순위. 정수 `1..255` 또는 `None`.
|
|
180
|
+
- `priority`: 기본 메시지 우선순위. 정수 `0..max_priority` 또는 `None`.
|
|
181
|
+
이 값만 지정하면 `max_priority`는 `255`로 설정됩니다.
|
|
182
|
+
|
|
183
|
+
`Subscription` 객체 생성이나 `consumer.subs()`는 큐를 선언하지 않습니다.
|
|
184
|
+
작업용 `declare()`는 일반 durable 큐와 선택적 DLQ를 준비하며,
|
|
185
|
+
스트림 큐나 Exchange 바인딩을 자동 생성하지 않습니다.
|
|
186
|
+
기존 큐의 선언 옵션이 다르면 실패하며 자동 삭제·재생성하지 않습니다.
|
|
187
|
+
|
|
188
|
+
## 워커 작업 우선순위
|
|
189
|
+
|
|
190
|
+
작업에 지정한 `Subscription`에 기본값 `priority`와 큐 최대값 `max_priority`를
|
|
191
|
+
함께 설정합니다. `Run`에는 별도의 `priority` 설정을 두지 않습니다.
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
class PriorityAdd(
|
|
195
|
+
Add,
|
|
196
|
+
parameters=Subscription(
|
|
197
|
+
queue='defstream.example.rabbitmq.priority.add',
|
|
198
|
+
qos=1,
|
|
199
|
+
max_priority=5,
|
|
200
|
+
priority=2,
|
|
201
|
+
),
|
|
202
|
+
):
|
|
203
|
+
pass
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- 워커 API `declare(task=PriorityAdd, broker=connection)`는 큐에
|
|
207
|
+
`x-max-priority=5`를 반영합니다. 기존 DLQ 설정도 보존합니다.
|
|
208
|
+
- `send(..., task=PriorityAdd, broker=connection)` 및
|
|
209
|
+
`request(..., task=PriorityAdd, broker=connection)`는 작업 기본값 `2`를 사용합니다.
|
|
210
|
+
호출에 `priority=0` 또는 다른 유효한 값을 지정하여 재정의할 수 있습니다.
|
|
211
|
+
- 기본값만 정의하면 큐 최대값은 `255`, 최대값만 정의하면 기본값은 `None`입니다.
|
|
212
|
+
호출별 값도 없으면 AMQP 우선순위 속성을 생략합니다.
|
|
213
|
+
- 워커 경로는 작업의 유효 최대값으로 검증합니다. 작업 설정 없이 호출에서만
|
|
214
|
+
지정하면 `0..255` 범위만 검증하며, 우선순위 큐 사전 선언은 호출자 책임입니다.
|
|
215
|
+
- 기존 저수준 `Queue.send`, `Exchange.send`와 `Queue.call`도 `priority=`를 받습니다.
|
|
216
|
+
이 경로는 작업 정의를 받지 않으므로 작업별 최대값은 검증하지 않습니다.
|
|
217
|
+
정수 `0..255`만 허용하며 `bool`은 거부합니다.
|
|
218
|
+
- 최대값을 늘릴수록 자원 비용이 증가하므로 필요한 수준만 지정하는 것을 권장합니다.
|
|
219
|
+
- 동일 큐를 여러 작업 정의에서 선언한다면 최대값을 동일하게 맞춰야 합니다.
|
|
220
|
+
기존 일반 큐나 최대값이 다른 큐를 재선언하면 RabbitMQ 오류가 전파됩니다.
|
|
221
|
+
자동 삭제하지 않으므로, 새 큐로 전환하거나 미처리 메시지를 보존한 후 운영자가
|
|
222
|
+
안전하게 재생성하고 생산자·소비자를 함께 전환해야 합니다.
|
|
223
|
+
- 높은 값이 먼저 전달되지만 이미 prefetch된 메시지나 실행 중인 작업은 선점하지
|
|
224
|
+
않습니다. 재전달, 다중 소비자에서는 완료 순서를 보장하지 않으며 낮은 우선순위
|
|
225
|
+
메시지가 오래 대기할 수 있습니다. Stream 및 Quorum 큐는 이번 지원 대상이 아닙니다.
|
|
226
|
+
|
|
227
|
+
## 동기 RPC
|
|
228
|
+
|
|
229
|
+
실행 중인 Worker가 있는 큐에 `call()`을 사용하면 `Run.run()`의 반환값을 받습니다.
|
|
230
|
+
아래 코드는 앞의 직접 연결 예제에서 `connect()`와 `close()` 사이에 사용하세요.
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
result = connection.queue('defstream.example.rabbitmq.add').call(
|
|
234
|
+
{'a': 10, 'b': 20},
|
|
235
|
+
timeout=5,
|
|
236
|
+
)
|
|
237
|
+
print(result)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- `timeout`은 **초** 단위이며 응답이 없으면 `TimeoutError`가 발생합니다.
|
|
241
|
+
이미 전달된 서버 작업을 취소하거나 전체 연결·정리 시간을 엄격히 제한하는 값은 아닙니다.
|
|
242
|
+
- 각 호출은 전용 연결과 임시 응답 큐를 사용하고 종료 시 정리합니다.
|
|
243
|
+
- 서버가 요청을 거부하면 `DefStream.Broker.RemoteError`가 발생합니다.
|
|
244
|
+
재큐잉은 최종 오류 응답 없이 재시도할 수 있습니다.
|
|
245
|
+
- 응답 발행과 요청 ACK는 원자적이지 않습니다. RPC에서도 중복 실행에 대비하세요.
|
|
246
|
+
|
|
247
|
+
공유 `Run` 클래스를 사용하는 애플리케이션은 코어의
|
|
248
|
+
`request(body, task=Add, broker=connection, timeout=5)`도 사용할 수 있습니다.
|
|
249
|
+
|
|
250
|
+
## Exchange와 스트림
|
|
251
|
+
|
|
252
|
+
- `connection.exchange(name)`은 `send()`와 `call()`을 제공합니다.
|
|
253
|
+
`event=`가 라우팅 키입니다. Exchange와 큐·바인딩을 먼저 선언하세요.
|
|
254
|
+
- Exchange RPC가 여러 큐로 라우팅되면 여러 곳에서 실행될 수 있으며,
|
|
255
|
+
클라이언트는 첫 일치 응답만 받습니다. 일반 RPC에는 단일 목적지를 사용하세요.
|
|
256
|
+
- `create_exchange()`, `bind_exchange_to_queue()`, `bind_exchange_to_exchange()`로 라우팅을 구성합니다.
|
|
257
|
+
각각에 대응하는 `delete_...` 또는 `unbind_...` 메서드도 있습니다.
|
|
258
|
+
- `create_stream()`으로 스트림 큐를 만든 뒤 `connection.stream(name)`의
|
|
259
|
+
`send()`와 `read(offset=0, timeout=1000)`을 사용합니다. 읽기 제한 시간은 밀리초입니다.
|
|
260
|
+
읽은 이벤트는 이터레이터가 다음 단계로 진행될 때 자동 ACK합니다.
|
|
261
|
+
- `delete_queue()`, `delete_stream()`, `delete_exchange()`는 리소스를 삭제하므로
|
|
262
|
+
애플리케이션 소유 리소스에만 사용하세요.
|
|
263
|
+
|
|
264
|
+
## 운영 시 주의사항
|
|
265
|
+
|
|
266
|
+
- 최소 한 번(at-least-once) 전달을 전제로 멱등 작업을 작성하세요.
|
|
267
|
+
- 무제한 재큐잉은 영구 오류 메시지의 반복 실행을 만들 수 있습니다. DLQ와 재시도 정책을 설계하세요.
|
|
268
|
+
- 소비자 연결에서 긴 작업을 직접 실행하지 말고 Worker의 풀을 사용하세요.
|
|
269
|
+
- 작업 훅에서 발행하려면 훅이 실행되는 스레드·프로세스 안에 별도 생산자 연결을 만드세요.
|
|
270
|
+
- `worker.stop()`은 처리 중인 작업과 ACK를 기다린 뒤 연결과 풀을 닫습니다.
|
|
271
|
+
강제 종료 또는 종료 대기 시간 제한은 제공하지 않습니다.
|
|
272
|
+
|
|
273
|
+
## 더 알아보기
|
|
274
|
+
|
|
275
|
+
- [DefStream 사용 설명서](https://github.com/yong5eon/DefStream#readme): 작업, 풀, 훅, 검증, Inspector, 대시보드·콘솔
|
|
276
|
+
- [큐·Exchange 예제](./sample/Sample.py)
|
|
277
|
+
- [독립 실행 RPC 예제](./sample/Sample.RPC.py)
|
|
278
|
+
- [스트림 예제](./sample/Sample.Stream.py)
|
|
279
|
+
- [릴리즈와 변경 내역](https://github.com/yong5eon/DefStream-RabbitMQ/releases)
|
|
280
|
+
|
|
281
|
+
GNU GPL v3 라이선스를 사용합니다. 자세한 조건은 [LICENSE](./LICENSE)를 확인하세요.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
DefStream/Broker/Implements/RabbitMQ/Configuration.py,sha256=neAQA2H7zjL5dZnnXjJfyP9iv0gB8wwqKAk6wqFNZLo,1059
|
|
2
|
+
DefStream/Broker/Implements/RabbitMQ/Connection.py,sha256=ArHJpoFJ3pN4Hn7Esp1Z9Ilq5V9OeLo9SOxjcG0Znj4,9758
|
|
3
|
+
DefStream/Broker/Implements/RabbitMQ/Consumer.py,sha256=c1-gOdlHYTC_szQazqlOtWZqHhH4P40myXjXGmWZ54E,5170
|
|
4
|
+
DefStream/Broker/Implements/RabbitMQ/Event.py,sha256=VyGORgRPiU7NIbrYV1a3MYMfof4DlerCwENc7AnacNg,1755
|
|
5
|
+
DefStream/Broker/Implements/RabbitMQ/Exchange.py,sha256=uKwQZZeXg4dJZpnzLBlRYyYxyZS4P6IuIcpMjnaP-3g,4884
|
|
6
|
+
DefStream/Broker/Implements/RabbitMQ/Policies.py,sha256=E0NA3zvO1h6BPr7CyMo9WPy6ztobuTd6fGUFgB8604o,90
|
|
7
|
+
DefStream/Broker/Implements/RabbitMQ/Queue.py,sha256=Gq6XrWhe15rzC60OhTYfyK9xKrLt5OFalkScliOujac,5503
|
|
8
|
+
DefStream/Broker/Implements/RabbitMQ/Serializer.py,sha256=ylwIBJ0blftq2W9usuYvjS3xfXovR8_9kP3O9DlXYxI,1575
|
|
9
|
+
DefStream/Broker/Implements/RabbitMQ/Stream.py,sha256=IHmQY-008c3vAP35ixlP9hG0DLs8nBHhu7NJbvURs34,2296
|
|
10
|
+
DefStream/Broker/Implements/RabbitMQ/Subscription.py,sha256=A1sCwWgytNYOIJ-D9PKps_1blxJNp1lGK0a1CDHh7Jw,1849
|
|
11
|
+
DefStream/Broker/Implements/RabbitMQ/__init__.py,sha256=Ndt5yNXcgecN1mj0Qv7M32LUFK96WKmSi88wKMB1ZdU,673
|
|
12
|
+
defstream_rabbitmq-0.1.2.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
13
|
+
defstream_rabbitmq-0.1.2.6.dist-info/METADATA,sha256=m-zt3qsFVSJhQ_WT3DIjWO70P7WYiKPWa-kysSekUwg,11806
|
|
14
|
+
defstream_rabbitmq-0.1.2.6.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
15
|
+
defstream_rabbitmq-0.1.2.6.dist-info/top_level.txt,sha256=zsnisIu5wHL4b7VM8e9AggG9KTSdUU4morFqpb8YWFs,10
|
|
16
|
+
defstream_rabbitmq-0.1.2.6.dist-info/RECORD,,
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: DefStream-RabbitMQ
|
|
3
|
-
Version: 0.1.1.2
|
|
4
|
-
Summary: RabbitMQ broker adapter for DefStream
|
|
5
|
-
Home-page: https://github.com/yong5eon/DefStream-RabbitMQ
|
|
6
|
-
Author: Heo Yongseon
|
|
7
|
-
Project-URL: Source, https://github.com/yong5eon/DefStream-RabbitMQ
|
|
8
|
-
Project-URL: Issues, https://github.com/yong5eon/DefStream-RabbitMQ/issues
|
|
9
|
-
Project-URL: Releases, https://github.com/yong5eon/DefStream-RabbitMQ/releases
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Requires-Python: >=3.9
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
|
-
Requires-Dist: DefStream>=0.1.0
|
|
20
|
-
Requires-Dist: pika>=1.3.2
|
|
21
|
-
Dynamic: author
|
|
22
|
-
Dynamic: classifier
|
|
23
|
-
Dynamic: description
|
|
24
|
-
Dynamic: description-content-type
|
|
25
|
-
Dynamic: home-page
|
|
26
|
-
Dynamic: license-file
|
|
27
|
-
Dynamic: project-url
|
|
28
|
-
Dynamic: requires-dist
|
|
29
|
-
Dynamic: requires-python
|
|
30
|
-
Dynamic: summary
|
|
31
|
-
|
|
32
|
-
# DefStream-RabbitMQ
|
|
33
|
-
|
|
34
|
-
## CI and PyPI releases
|
|
35
|
-
|
|
36
|
-
The `CI` workflow tests PRs targeting `master` and pushes to `master` on Python
|
|
37
|
-
3.9 through 3.14. It builds all three DefStream packages from source, installs
|
|
38
|
-
their wheels in a clean environment, and runs this repository's tests with
|
|
39
|
-
RabbitMQ 4.1 and Redis 7.4 service containers. The current repository uses the
|
|
40
|
-
event commit; sibling repositories use their `master` branches, with resolved
|
|
41
|
-
commit IDs recorded in the log. All three GitHub repositories must be accessible.
|
|
42
|
-
This bootstrap setup does not require existing PyPI releases and does not
|
|
43
|
-
certify compatibility with previously published dependencies.
|
|
44
|
-
|
|
45
|
-
There is no `VERSION` or `pyproject.toml` file. `setup.py` configures
|
|
46
|
-
`setuptools-scm` via `setup_requires`; `python -m build` resolves the build
|
|
47
|
-
dependency in isolation. This legacy declaration may emit a deprecation warning.
|
|
48
|
-
`setuptools-scm` derives versions from Git tags.
|
|
49
|
-
CI fetches full history and creates a local candidate tag
|
|
50
|
-
`<RELEASE_SERIES>.<PATCH>.<github.run_number>` (for example, `0.1.3.123`) on
|
|
51
|
-
every `master` push. Source changes increment PATCH by one; all other changes
|
|
52
|
-
keep MAJOR.MINOR.PATCH. BUILD is always the Actions run number:
|
|
53
|
-
`0.1.3.123` -> `0.1.3.124` (docs) -> `0.1.4.125` (source).
|
|
54
|
-
The highest matching version in pre-push history supplies the base, keeping
|
|
55
|
-
reruns stable. The four-part value is the full public PyPI version.
|
|
56
|
-
New tags have no `v` prefix; existing `v` tags remain readable.
|
|
57
|
-
PRs only run tests using their Git-derived development version without a tag.
|
|
58
|
-
The complete push range is compared, including additions, deletions, and
|
|
59
|
-
renames. Changes only to tests, docs, samples, workflows, or `setup.py` increase
|
|
60
|
-
only BUILD. PyPI files cannot be overwritten; every upload has a distinct
|
|
61
|
-
version identifier. Change
|
|
62
|
-
`RELEASE_SERIES` in the workflow to start a new major/minor series. No version
|
|
63
|
-
commit or version-update PR is created; run numbers can have gaps.
|
|
64
|
-
|
|
65
|
-
After all tests pass, the publish job pushes the release tag to the tested
|
|
66
|
-
commit before uploading the verified artifacts. A tag may exist if uploading
|
|
67
|
-
subsequently fails; retry the run and check PyPI for publication status.
|
|
68
|
-
Existing tags on other commits are never overwritten. Allow the workflow's
|
|
69
|
-
`GITHUB_TOKEN` to write contents and permit numeric four-part tags
|
|
70
|
-
in any tag rulesets.
|
|
71
|
-
|
|
72
|
-
After PyPI upload succeeds (or a rerun confirms the version is fully
|
|
73
|
-
published), CI creates a GitHub Release titled and tagged with the same
|
|
74
|
-
version, with automatically generated notes and the verified wheel and sdist
|
|
75
|
-
attached. New releases remain drafts until both assets are uploaded. A retry
|
|
76
|
-
reuses the release, replaces matching assets with the verified files, and
|
|
77
|
-
publishes it. PyPI upload failures prevent this step. The existing write-enabled
|
|
78
|
-
`GITHUB_TOKEN` is sufficient; no extra token secret is required. PyPI's project
|
|
79
|
-
links include the GitHub Releases page for change history.
|
|
80
|
-
|
|
81
|
-
Fetch tags with `git fetch --tags` for local builds. Tagged commits produce
|
|
82
|
-
release versions; later commits produce development versions, with local
|
|
83
|
-
suffixes for dirty trees. Build from a Git checkout or a published sdist, not
|
|
84
|
-
a GitHub source ZIP without Git metadata. Installed versions are available via
|
|
85
|
-
`importlib.metadata.version('DefStream-RabbitMQ')`. Before migration, tag the
|
|
86
|
-
exact source commits of existing PyPI releases in all three repositories,
|
|
87
|
-
using their version numbers as tags.
|
|
88
|
-
Untagged SCM dependencies may resolve below their required minimum version;
|
|
89
|
-
initial release tags also provide the starting PATCH for numeric builds.
|
|
90
|
-
A tag such as `0.1.3` must name the commit used to publish that version, not
|
|
91
|
-
an arbitrary current commit. Adding that tag does not edit sources or upload
|
|
92
|
-
anything to PyPI.
|
|
93
|
-
A new release series needs a source change or an existing matching release tag
|
|
94
|
-
before it can produce builds. Its first source release starts at PATCH 0.
|
|
95
|
-
Build counter regressions fail explicitly. Legacy `.postN` tags remain
|
|
96
|
-
readable; numeric builds sort above post releases of a three-part base.
|
|
97
|
-
|
|
98
|
-
Only after all six Python checks pass does a separate publish job upload the
|
|
99
|
-
exact Python 3.13 build artifacts. A fully published version is skipped on a
|
|
100
|
-
rerun; first-attempt collisions, incomplete releases, and unexpected network
|
|
101
|
-
errors fail. Active runs are not cancelled; older pending runs may be superseded.
|
|
102
|
-
|
|
103
|
-
Configure `PYPI_API_TOKEN` as a repository Actions secret or a secret in the
|
|
104
|
-
`pypi` environment. Restrict that environment to `master`; omit approval rules
|
|
105
|
-
for fully automatic releases. Protect `master` with required PRs and all six
|
|
106
|
-
`Test Python 3.x` checks, not the push-only `Publish PyPI` job. Never commit the
|
|
107
|
-
token. Publish the core before this adapter so users can resolve its dependency.
|
|
108
|
-
|
|
109
|
-
RabbitMQ broker adapter for DefStream, distributed separately from the core.
|
|
110
|
-
Requires Python 3.9 or newer.
|
|
111
|
-
|
|
112
|
-
## Installation
|
|
113
|
-
|
|
114
|
-
```shell
|
|
115
|
-
pip install DefStream-RabbitMQ
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
This installs `DefStream>=0.1.0` and `pika>=1.3.2`. The distribution name is
|
|
119
|
-
`DefStream-RabbitMQ`; the Python import path remains
|
|
120
|
-
`DefStream.Broker.Implements.RabbitMQ`.
|
|
121
|
-
|
|
122
|
-
## Usage
|
|
123
|
-
|
|
124
|
-
```python
|
|
125
|
-
from DefStream.Broker.Implements.RabbitMQ import (
|
|
126
|
-
Configuration,
|
|
127
|
-
Connection,
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
broker = Connection(Configuration(
|
|
131
|
-
host='127.0.0.1',
|
|
132
|
-
port=5672,
|
|
133
|
-
username='guest',
|
|
134
|
-
password='guest',
|
|
135
|
-
))
|
|
136
|
-
broker.connect()
|
|
137
|
-
try:
|
|
138
|
-
broker.create_queue('tasks')
|
|
139
|
-
broker.queue('tasks').send({'message': 'hello'})
|
|
140
|
-
finally:
|
|
141
|
-
broker.close()
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
A reachable RabbitMQ server is required. Use connections and their resources
|
|
145
|
-
on the thread that owns them.
|
|
146
|
-
|
|
147
|
-
The adapter provides queues, exchanges, streams, subscriptions, error policies,
|
|
148
|
-
and synchronous queue/exchange RPC. Use its `Connection` with
|
|
149
|
-
`DefStream.Worker.Worker` for worker execution.
|
|
150
|
-
|
|
151
|
-
## Source layout
|
|
152
|
-
|
|
153
|
-
The contents of the former `DefStream/src/Broker/Implements/RabbitMQ` directory
|
|
154
|
-
now live directly in this project's [src](./src) directory. Packaging maps that
|
|
155
|
-
directory to `DefStream.Broker.Implements.RabbitMQ`; this distribution does not
|
|
156
|
-
own or overwrite the parent packages supplied by DefStream.
|
|
157
|
-
|
|
158
|
-
## Development
|
|
159
|
-
|
|
160
|
-
With the core and both adapters checked out as sibling directories, run this
|
|
161
|
-
from their common parent using your virtual environment's Python:
|
|
162
|
-
|
|
163
|
-
```powershell
|
|
164
|
-
python -m pip install --config-settings editable_mode=strict -e .\DefStream
|
|
165
|
-
python -m pip install -e .\DefStream-RabbitMQ -e .\DefStream-Redis
|
|
166
|
-
python -m unittest discover -s .\DefStream-RabbitMQ\test -p "test_*.py"
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
The core uses strict editable mode to prevent the adapters' editable namespace
|
|
170
|
-
entries from masking its packages. Keep the core's generated `build` link tree;
|
|
171
|
-
reinstall the core after adding or removing its modules. Adapters use default
|
|
172
|
-
editable mode.
|
|
173
|
-
|
|
174
|
-
RabbitMQ-specific tests live in this project's `test` directory, covering
|
|
175
|
-
resource methods, subscriptions, consumers, RPC, and broker integration.
|
|
176
|
-
Broker examples live in `sample`. Shared Worker, Inspector, and cross-adapter
|
|
177
|
-
contract tests remain in the DefStream repository and require both adapters.
|
|
178
|
-
|
|
179
|
-
Run `python -m unittest discover -s test -p "test_*.py"` from this project
|
|
180
|
-
directory after installation. Integration tests are opt-in via
|
|
181
|
-
`DEFSTREAM_RABBITMQ_TESTS=1`; ordinary unit tests do not require a running broker
|
|
182
|
-
or the Redis adapter.
|
|
183
|
-
|
|
184
|
-
Do not combine editable installs with a `site-packages/DefStream` link pointing
|
|
185
|
-
directly at the core source: installing adapter files through that link can
|
|
186
|
-
write into the core checkout. Remove such a link before installing the projects.
|
|
187
|
-
Reinstall after changing package metadata or dependencies.
|
|
188
|
-
|
|
189
|
-
## License
|
|
190
|
-
|
|
191
|
-
See [LICENSE](./LICENSE), copied unchanged from DefStream.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
DefStream/Broker/Implements/RabbitMQ/Configuration.py,sha256=UFE3BCny4KXmLqEUuyDNXUvYcy9yleqCNio1LF1u_y8,1046
|
|
2
|
-
DefStream/Broker/Implements/RabbitMQ/Connection.py,sha256=cDCfzKmYHs5WMQZvmvNSq7EAuLVRtHVhSBuYHLmDNks,8926
|
|
3
|
-
DefStream/Broker/Implements/RabbitMQ/Consumer.py,sha256=KUBhqiDujMKzcFuyPyzsbDv-5uMmrIYFAgRJ9KdWBwk,5182
|
|
4
|
-
DefStream/Broker/Implements/RabbitMQ/Event.py,sha256=LmSiaSUqJF_kx7v78tt-bawy797z5Q-lM5OO0hnIQcc,1747
|
|
5
|
-
DefStream/Broker/Implements/RabbitMQ/Exchange.py,sha256=MjOdtn1Aeh20mzGZOsa0MxMlpePpyQkz49_VDlf_7oM,4815
|
|
6
|
-
DefStream/Broker/Implements/RabbitMQ/Policies.py,sha256=kT7vreCclwsu5hMAFkDldsNBktuOMB611biOePk7Lr4,85
|
|
7
|
-
DefStream/Broker/Implements/RabbitMQ/Queue.py,sha256=cQTO988qlL0K-ZMgW71jYFoGigcu0KVXhGnjltHMJSU,5325
|
|
8
|
-
DefStream/Broker/Implements/RabbitMQ/Serializer.py,sha256=ylwIBJ0blftq2W9usuYvjS3xfXovR8_9kP3O9DlXYxI,1575
|
|
9
|
-
DefStream/Broker/Implements/RabbitMQ/Stream.py,sha256=9E7R_bX_kDZ3VIH7hkMpP-Z7zGbJTonU8V6q_KT3YRI,2283
|
|
10
|
-
DefStream/Broker/Implements/RabbitMQ/Subscription.py,sha256=0ACs8skbn_s9UfricBDf59hT0F6G3ljO4aUrkpLuI9g,1284
|
|
11
|
-
DefStream/Broker/Implements/RabbitMQ/__init__.py,sha256=Ndt5yNXcgecN1mj0Qv7M32LUFK96WKmSi88wKMB1ZdU,673
|
|
12
|
-
defstream_rabbitmq-0.1.1.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
13
|
-
defstream_rabbitmq-0.1.1.2.dist-info/METADATA,sha256=VCEpTp6CDluZN9ptt2hi4a1nmROppwPCM0J_M8_cQRo,8701
|
|
14
|
-
defstream_rabbitmq-0.1.1.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
15
|
-
defstream_rabbitmq-0.1.1.2.dist-info/top_level.txt,sha256=zsnisIu5wHL4b7VM8e9AggG9KTSdUU4morFqpb8YWFs,10
|
|
16
|
-
defstream_rabbitmq-0.1.1.2.dist-info/RECORD,,
|
|
File without changes
|
{defstream_rabbitmq-0.1.1.2.dist-info → defstream_rabbitmq-0.1.2.6.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|