DefStream-RabbitMQ 0.1.1.3__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.

@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ... import Configuration as BaseConfiguration
3
+ from DefStream.Broker import Configuration as BaseConfiguration
4
4
 
5
5
  from .Serializer import (
6
6
  Encoder,
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ...Connection import (
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__(self, key: Any) -> Any:
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: Any,
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: Any,
170
- parameters: Any,
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: Any,
203
- parameters: Any,
223
+ body: AnyValue,
224
+ parameters: AnyValue,
204
225
  timeout: float = 5,
205
- ) -> Any:
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 ... import (
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,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ...Event import (
3
+ from DefStream.Broker import (
4
4
  Event as BaseEvent,
5
5
  EventHandler as BaseEventHandler,
6
6
  )
@@ -1,15 +1,16 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ... import (
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,4 +1,4 @@
1
- from ...Policies import (
1
+ from DefStream.Broker import (
2
2
  Requeue,
3
3
  Reject,
4
4
  )
@@ -1,9 +1,11 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ... import (
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,
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from ... import (
3
+ from DefStream.Broker import (
4
4
  Sendable,
5
5
  Readable,
6
6
  )
@@ -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':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DefStream-RabbitMQ
3
- Version: 0.1.1.3
3
+ Version: 0.1.2.6
4
4
  Summary: RabbitMQ broker adapter for DefStream
5
5
  Home-page: https://github.com/yong5eon/DefStream-RabbitMQ
6
6
  Author: Heo Yongseon
@@ -176,12 +176,54 @@ Worker는 실행과 완료 훅이 끝난 뒤 ACK하고, 실패하면 지정한
176
176
  Worker의 공유 풀 크기와 별개입니다.
177
177
  - `error`: `declare()`가 생성하고 연결할 오류 큐 이름. 거부된 메시지의 DLQ입니다.
178
178
  - `offset`: RabbitMQ 스트림 구독에 사용할 정수 오프셋.
179
+ - `max_priority`: classic 작업 큐의 최대 우선순위. 정수 `1..255` 또는 `None`.
180
+ - `priority`: 기본 메시지 우선순위. 정수 `0..max_priority` 또는 `None`.
181
+ 이 값만 지정하면 `max_priority`는 `255`로 설정됩니다.
179
182
 
180
183
  `Subscription` 객체 생성이나 `consumer.subs()`는 큐를 선언하지 않습니다.
181
184
  작업용 `declare()`는 일반 durable 큐와 선택적 DLQ를 준비하며,
182
185
  스트림 큐나 Exchange 바인딩을 자동 생성하지 않습니다.
183
186
  기존 큐의 선언 옵션이 다르면 실패하며 자동 삭제·재생성하지 않습니다.
184
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
+
185
227
  ## 동기 RPC
186
228
 
187
229
  실행 중인 Worker가 있는 큐에 `call()`을 사용하면 `Run.run()`의 반환값을 받습니다.
@@ -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,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.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
13
- defstream_rabbitmq-0.1.1.3.dist-info/METADATA,sha256=SRhV3AAy1XwU3uwaI-tFnFMZjqOP1zEmghZorysWznc,9242
14
- defstream_rabbitmq-0.1.1.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
15
- defstream_rabbitmq-0.1.1.3.dist-info/top_level.txt,sha256=zsnisIu5wHL4b7VM8e9AggG9KTSdUU4morFqpb8YWFs,10
16
- defstream_rabbitmq-0.1.1.3.dist-info/RECORD,,