DefStream 0.1.6__tar.gz → 0.1.7__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.
- {defstream-0.1.6 → defstream-0.1.7}/DefStream.egg-info/PKG-INFO +23 -8
- {defstream-0.1.6 → defstream-0.1.7}/DefStream.egg-info/SOURCES.txt +1 -0
- {defstream-0.1.6 → defstream-0.1.7}/PKG-INFO +23 -8
- {defstream-0.1.6 → defstream-0.1.7}/README.en.md +23 -7
- {defstream-0.1.6 → defstream-0.1.7}/README.md +22 -7
- {defstream-0.1.6 → defstream-0.1.7}/issues/feature/1/README.md +3 -3
- {defstream-0.1.6 → defstream-0.1.7}/issues/fix/3/IMPLEMENTS.md +99 -0
- defstream-0.1.7/issues/fix/3/README.md +94 -0
- {defstream-0.1.6 → defstream-0.1.7}/issues/fix/3/REQUIREMENTS.md +27 -1
- defstream-0.1.7/issues/fix/3/ci.refs.json +4 -0
- {defstream-0.1.6 → defstream-0.1.7}/sample/Worker/RabbitMQ/Worker.py +2 -2
- {defstream-0.1.6 → defstream-0.1.7}/sample/Worker/Redis/Sample.py +2 -2
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Connection.py +20 -5
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/__init__.py +4 -2
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Console.py +4 -15
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Message.py +17 -16
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/__init__.py +2 -2
- {defstream-0.1.6 → defstream-0.1.7}/test/test_inspector.py +1 -1
- {defstream-0.1.6 → defstream-0.1.7}/test/test_inspector_console.py +2 -2
- {defstream-0.1.6 → defstream-0.1.7}/test/test_protocol_contracts.py +116 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_task_messages.py +120 -21
- {defstream-0.1.6 → defstream-0.1.7}/test/test_task_priorities.py +9 -9
- defstream-0.1.6/issues/fix/3/README.md +0 -47
- {defstream-0.1.6 → defstream-0.1.7}/.github/workflows/ci.yml +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/.gitignore +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/DefStream.egg-info/dependency_links.txt +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/DefStream.egg-info/requires.txt +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/DefStream.egg-info/top_level.txt +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/LICENSE +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/issues/feature/1/IMPLEMENTS.md +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/issues/feature/1/REQUIREMENTS.md +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/issues/feature/1/TASK.md +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/issues/feature/1/ci.refs.json +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/sample/Broker/Sample.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/sample/Worker/RabbitMQ/Client.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/sample/Worker/RabbitMQ/Tasks.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/sample/Worker/Sample.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/setup.cfg +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/setup.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Configuration.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Consumer.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Errors.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Event.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Implements/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Policies.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Priority.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Broker/Protocol.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Descriptor/DataObject.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Descriptor/Types.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Descriptor/Value.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Descriptor/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extension.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Console.html +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Dashboard.html +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Dashboard.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/HealthCheck.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Metrics.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/Specifications.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Extensions/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Inspector.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/Response.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Inspector/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Pattern.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Array.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Common.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Compare.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Condition.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/DataObject.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/DateTime.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Number.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Object.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Size.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/String.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/Type.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Patterns/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Validate.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/Validator.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Validator/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Executor.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Pool.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Run.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Specification.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Startup.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/Worker/Worker.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/src/__init__.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_dashboard.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_dashboard_ui.cjs +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_lifecycle_hooks.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_pool_callbacks.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_process_signals.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_release_workflow.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_runner_hooks.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_specifications.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_worker.py +0 -0
- {defstream-0.1.6 → defstream-0.1.7}/test/test_worker_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -181,7 +181,7 @@ Worker가 실행 중인 상태에서 다른 터미널에서 실행하세요.
|
|
|
181
181
|
|
|
182
182
|
```python
|
|
183
183
|
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection
|
|
184
|
-
from DefStream.Worker import
|
|
184
|
+
from DefStream.Worker import emit, request
|
|
185
185
|
from tasks import Add
|
|
186
186
|
|
|
187
187
|
|
|
@@ -193,7 +193,7 @@ connection = Connection(Configuration(
|
|
|
193
193
|
))
|
|
194
194
|
try:
|
|
195
195
|
connection.connect()
|
|
196
|
-
message_id =
|
|
196
|
+
message_id = emit(
|
|
197
197
|
{'a': 10, 'b': 20},
|
|
198
198
|
task=Add,
|
|
199
199
|
broker=connection,
|
|
@@ -214,7 +214,7 @@ finally:
|
|
|
214
214
|
python client.py
|
|
215
215
|
```
|
|
216
216
|
|
|
217
|
-
`
|
|
217
|
+
`emit()`와 `request()`는 **각각 별도의 작업을 발행**합니다. 위 예제는 덧셈을 두 번 실행하며,
|
|
218
218
|
`request()`의 결과는 `30`입니다. `request()`의 제한 시간은 초 단위이고,
|
|
219
219
|
시간이 초과되어도 이미 전달된 작업은 취소되지 않습니다.
|
|
220
220
|
|
|
@@ -225,14 +225,20 @@ python client.py
|
|
|
225
225
|
| 함수 | 역할 | 연결 관리 |
|
|
226
226
|
| --- | --- | --- |
|
|
227
227
|
| `declare(task=..., broker=...)` | 작업의 큐·구독 리소스 선언 | 호출자가 연결·종료 |
|
|
228
|
-
| `
|
|
228
|
+
| `emit(body, task=..., broker=...)` | 작업 목적지로 단방향 메시지 발행 | 호출자가 연결·종료 |
|
|
229
229
|
| `request(body, task=..., broker=..., timeout=5)` | 작업 결과를 동기 RPC로 요청 | 호출자가 연결·종료; RabbitMQ만 지원 |
|
|
230
230
|
|
|
231
231
|
세 함수는 `DefStream.Worker`에서 가져옵니다. 전달된 연결을 자동으로 열거나 닫지 않으며,
|
|
232
|
-
`
|
|
232
|
+
`emit()`와 `request()`는 목적지를 자동 선언하지 않습니다.
|
|
233
233
|
수신 Worker 또는 별도의 준비 단계에서 먼저 `declare()`를 호출하세요.
|
|
234
234
|
하나의 연결을 같은 소유 스레드에서 여러 발행에 재사용할 수 있습니다.
|
|
235
235
|
|
|
236
|
+
세 함수 모두 공통 `Connection`을 받고, 내부에서 선언·발행·RPC 지원 여부를 확인합니다.
|
|
237
|
+
지원하지 않는 기능은 `NotImplementedError`로 실패합니다.
|
|
238
|
+
기존 작업 발행 함수와 연결의 `send`는 `emit`으로 이름이 바뀌었습니다.
|
|
239
|
+
사용자 정의 브로커의 작업 발행 계약도 `TaskSender.send` 대신 `Emittable.emit`을 사용하세요.
|
|
240
|
+
큐·Exchange·Stream의 저수준 `Sendable.send()`와 RPC `Callable.call()`은 그대로입니다.
|
|
241
|
+
|
|
236
242
|
작업 본문은 **문자열 키를 가진 매핑**이어야 하며, 반환값은 어댑터가 직렬화할 수 있어야 합니다.
|
|
237
243
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
238
244
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
@@ -250,7 +256,7 @@ from DefStream.Worker import (
|
|
|
250
256
|
Run,
|
|
251
257
|
declare,
|
|
252
258
|
request,
|
|
253
|
-
|
|
259
|
+
emit,
|
|
254
260
|
)
|
|
255
261
|
|
|
256
262
|
|
|
@@ -275,7 +281,7 @@ declare(
|
|
|
275
281
|
task=Add,
|
|
276
282
|
broker=broker,
|
|
277
283
|
)
|
|
278
|
-
|
|
284
|
+
emit(
|
|
279
285
|
{'a': 10, 'b': 20},
|
|
280
286
|
task=Add,
|
|
281
287
|
broker=broker,
|
|
@@ -315,6 +321,10 @@ result = request(
|
|
|
315
321
|
브로커 리소스를 직접 사용할 때의 공통 메서드는 다음과 같습니다.
|
|
316
322
|
모든 리소스가 모든 메서드를 지원하는 것은 아닙니다.
|
|
317
323
|
|
|
324
|
+
연결의 `exchange()`·`queue()`·`stream()`·`consumer()` 지원 여부는 각각
|
|
325
|
+
`GetExchange`·`GetQueue`·`GetStream`·`GetConsumer`로 `isinstance` 또는 `issubclass`
|
|
326
|
+
검사할 수 있습니다. 이 계약들은 `DefStream.Broker`에서 가져옵니다.
|
|
327
|
+
|
|
318
328
|
| 메서드 | 의미 | 제한 시간 단위 |
|
|
319
329
|
| --- | --- | --- |
|
|
320
330
|
| `send(body)` | 메시지 발행 | 어댑터별 설정 |
|
|
@@ -579,6 +589,11 @@ inspector = Inspector(
|
|
|
579
589
|
Inspector 자체는 TLS를 제공하지 않으며 공개 웹 서버가 아닙니다.
|
|
580
590
|
콘솔의 연결 팩터리는 호출마다 새 연결을 반환해야 하고 Worker 연결을 공유하면 안 됩니다.
|
|
581
591
|
|
|
592
|
+
Console의 `broker` 인자는 `DefStream.Broker.BrokerFactory` 계약을 사용합니다.
|
|
593
|
+
이 계약의 `__call__() -> Connection`은 인자 없이 새 연결을 반환합니다.
|
|
594
|
+
위의 `create_connection` 같은 함수나 람다도 그대로 전달할 수 있으며,
|
|
595
|
+
클래스로 구현할 때는 `BrokerFactory`를 상속하고 `__call__`을 구현할 수 있습니다.
|
|
596
|
+
|
|
582
597
|
## 브로커 선택과 운영 주의사항
|
|
583
598
|
|
|
584
599
|
| 기능 | RabbitMQ | Redis Streams |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -181,7 +181,7 @@ Worker가 실행 중인 상태에서 다른 터미널에서 실행하세요.
|
|
|
181
181
|
|
|
182
182
|
```python
|
|
183
183
|
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection
|
|
184
|
-
from DefStream.Worker import
|
|
184
|
+
from DefStream.Worker import emit, request
|
|
185
185
|
from tasks import Add
|
|
186
186
|
|
|
187
187
|
|
|
@@ -193,7 +193,7 @@ connection = Connection(Configuration(
|
|
|
193
193
|
))
|
|
194
194
|
try:
|
|
195
195
|
connection.connect()
|
|
196
|
-
message_id =
|
|
196
|
+
message_id = emit(
|
|
197
197
|
{'a': 10, 'b': 20},
|
|
198
198
|
task=Add,
|
|
199
199
|
broker=connection,
|
|
@@ -214,7 +214,7 @@ finally:
|
|
|
214
214
|
python client.py
|
|
215
215
|
```
|
|
216
216
|
|
|
217
|
-
`
|
|
217
|
+
`emit()`와 `request()`는 **각각 별도의 작업을 발행**합니다. 위 예제는 덧셈을 두 번 실행하며,
|
|
218
218
|
`request()`의 결과는 `30`입니다. `request()`의 제한 시간은 초 단위이고,
|
|
219
219
|
시간이 초과되어도 이미 전달된 작업은 취소되지 않습니다.
|
|
220
220
|
|
|
@@ -225,14 +225,20 @@ python client.py
|
|
|
225
225
|
| 함수 | 역할 | 연결 관리 |
|
|
226
226
|
| --- | --- | --- |
|
|
227
227
|
| `declare(task=..., broker=...)` | 작업의 큐·구독 리소스 선언 | 호출자가 연결·종료 |
|
|
228
|
-
| `
|
|
228
|
+
| `emit(body, task=..., broker=...)` | 작업 목적지로 단방향 메시지 발행 | 호출자가 연결·종료 |
|
|
229
229
|
| `request(body, task=..., broker=..., timeout=5)` | 작업 결과를 동기 RPC로 요청 | 호출자가 연결·종료; RabbitMQ만 지원 |
|
|
230
230
|
|
|
231
231
|
세 함수는 `DefStream.Worker`에서 가져옵니다. 전달된 연결을 자동으로 열거나 닫지 않으며,
|
|
232
|
-
`
|
|
232
|
+
`emit()`와 `request()`는 목적지를 자동 선언하지 않습니다.
|
|
233
233
|
수신 Worker 또는 별도의 준비 단계에서 먼저 `declare()`를 호출하세요.
|
|
234
234
|
하나의 연결을 같은 소유 스레드에서 여러 발행에 재사용할 수 있습니다.
|
|
235
235
|
|
|
236
|
+
세 함수 모두 공통 `Connection`을 받고, 내부에서 선언·발행·RPC 지원 여부를 확인합니다.
|
|
237
|
+
지원하지 않는 기능은 `NotImplementedError`로 실패합니다.
|
|
238
|
+
기존 작업 발행 함수와 연결의 `send`는 `emit`으로 이름이 바뀌었습니다.
|
|
239
|
+
사용자 정의 브로커의 작업 발행 계약도 `TaskSender.send` 대신 `Emittable.emit`을 사용하세요.
|
|
240
|
+
큐·Exchange·Stream의 저수준 `Sendable.send()`와 RPC `Callable.call()`은 그대로입니다.
|
|
241
|
+
|
|
236
242
|
작업 본문은 **문자열 키를 가진 매핑**이어야 하며, 반환값은 어댑터가 직렬화할 수 있어야 합니다.
|
|
237
243
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
238
244
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
@@ -250,7 +256,7 @@ from DefStream.Worker import (
|
|
|
250
256
|
Run,
|
|
251
257
|
declare,
|
|
252
258
|
request,
|
|
253
|
-
|
|
259
|
+
emit,
|
|
254
260
|
)
|
|
255
261
|
|
|
256
262
|
|
|
@@ -275,7 +281,7 @@ declare(
|
|
|
275
281
|
task=Add,
|
|
276
282
|
broker=broker,
|
|
277
283
|
)
|
|
278
|
-
|
|
284
|
+
emit(
|
|
279
285
|
{'a': 10, 'b': 20},
|
|
280
286
|
task=Add,
|
|
281
287
|
broker=broker,
|
|
@@ -315,6 +321,10 @@ result = request(
|
|
|
315
321
|
브로커 리소스를 직접 사용할 때의 공통 메서드는 다음과 같습니다.
|
|
316
322
|
모든 리소스가 모든 메서드를 지원하는 것은 아닙니다.
|
|
317
323
|
|
|
324
|
+
연결의 `exchange()`·`queue()`·`stream()`·`consumer()` 지원 여부는 각각
|
|
325
|
+
`GetExchange`·`GetQueue`·`GetStream`·`GetConsumer`로 `isinstance` 또는 `issubclass`
|
|
326
|
+
검사할 수 있습니다. 이 계약들은 `DefStream.Broker`에서 가져옵니다.
|
|
327
|
+
|
|
318
328
|
| 메서드 | 의미 | 제한 시간 단위 |
|
|
319
329
|
| --- | --- | --- |
|
|
320
330
|
| `send(body)` | 메시지 발행 | 어댑터별 설정 |
|
|
@@ -579,6 +589,11 @@ inspector = Inspector(
|
|
|
579
589
|
Inspector 자체는 TLS를 제공하지 않으며 공개 웹 서버가 아닙니다.
|
|
580
590
|
콘솔의 연결 팩터리는 호출마다 새 연결을 반환해야 하고 Worker 연결을 공유하면 안 됩니다.
|
|
581
591
|
|
|
592
|
+
Console의 `broker` 인자는 `DefStream.Broker.BrokerFactory` 계약을 사용합니다.
|
|
593
|
+
이 계약의 `__call__() -> Connection`은 인자 없이 새 연결을 반환합니다.
|
|
594
|
+
위의 `create_connection` 같은 함수나 람다도 그대로 전달할 수 있으며,
|
|
595
|
+
클래스로 구현할 때는 `BrokerFactory`를 상속하고 `__call__`을 구현할 수 있습니다.
|
|
596
|
+
|
|
582
597
|
## 브로커 선택과 운영 주의사항
|
|
583
598
|
|
|
584
599
|
| 기능 | RabbitMQ | Redis Streams |
|
|
@@ -151,7 +151,7 @@ Run this in another terminal while the Worker is running.
|
|
|
151
151
|
|
|
152
152
|
```python
|
|
153
153
|
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection
|
|
154
|
-
from DefStream.Worker import
|
|
154
|
+
from DefStream.Worker import emit, request
|
|
155
155
|
from tasks import Add
|
|
156
156
|
|
|
157
157
|
|
|
@@ -163,7 +163,7 @@ connection = Connection(Configuration(
|
|
|
163
163
|
))
|
|
164
164
|
try:
|
|
165
165
|
connection.connect()
|
|
166
|
-
message_id =
|
|
166
|
+
message_id = emit(
|
|
167
167
|
{'a': 10, 'b': 20},
|
|
168
168
|
task=Add,
|
|
169
169
|
broker=connection,
|
|
@@ -184,7 +184,7 @@ finally:
|
|
|
184
184
|
python client.py
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
`
|
|
187
|
+
`emit()` and `request()` **each publish a separate task**. This example performs
|
|
188
188
|
the addition twice; `request()` returns `30`. The request timeout is in seconds
|
|
189
189
|
and does not cancel work that has already been delivered.
|
|
190
190
|
|
|
@@ -195,14 +195,21 @@ and does not cancel work that has already been delivered.
|
|
|
195
195
|
| Function | Purpose | Connection ownership |
|
|
196
196
|
| --- | --- | --- |
|
|
197
197
|
| `declare(task=..., broker=...)` | Declare task queues and subscription resources | Caller connects and closes |
|
|
198
|
-
| `
|
|
198
|
+
| `emit(body, task=..., broker=...)` | Publish a one-way message to a task | Caller connects and closes |
|
|
199
199
|
| `request(body, task=..., broker=..., timeout=5)` | Request a task result synchronously | Caller connects and closes; RabbitMQ only |
|
|
200
200
|
|
|
201
201
|
Import these functions from `DefStream.Worker`. They do not connect or close
|
|
202
|
-
the supplied connection. Neither `
|
|
202
|
+
the supplied connection. Neither `emit()` nor `request()` declares destinations.
|
|
203
203
|
Call `declare()` in the receiving Worker's setup or a separate provisioning step.
|
|
204
204
|
Reuse a connection for multiple publications on its owning thread.
|
|
205
205
|
|
|
206
|
+
All three helpers accept the common `Connection` type and check declaration,
|
|
207
|
+
emission, or RPC support internally. Unsupported operations raise `NotImplementedError`.
|
|
208
|
+
The task helper and connection method previously named `send` are now named `emit`.
|
|
209
|
+
Custom brokers should use `Emittable.emit` instead of `TaskSender.send` for task emission.
|
|
210
|
+
Low-level `Sendable.send()` and RPC `Callable.call()` on queues, exchanges, and streams
|
|
211
|
+
remain unchanged.
|
|
212
|
+
|
|
206
213
|
Task bodies must be **mappings with string keys**. Return values must be
|
|
207
214
|
serializable by the adapter. A Worker cannot register multiple tasks for the
|
|
208
215
|
same queue: routing selects tasks by queue, not by a type field in the message.
|
|
@@ -220,7 +227,7 @@ from DefStream.Worker import (
|
|
|
220
227
|
Run,
|
|
221
228
|
declare,
|
|
222
229
|
request,
|
|
223
|
-
|
|
230
|
+
emit,
|
|
224
231
|
)
|
|
225
232
|
|
|
226
233
|
|
|
@@ -245,7 +252,7 @@ declare(
|
|
|
245
252
|
task=Add,
|
|
246
253
|
broker=broker,
|
|
247
254
|
)
|
|
248
|
-
|
|
255
|
+
emit(
|
|
249
256
|
{'a': 10, 'b': 20},
|
|
250
257
|
task=Add,
|
|
251
258
|
broker=broker,
|
|
@@ -287,6 +294,10 @@ result = request(
|
|
|
287
294
|
The common resource operations below apply when accessing a broker directly.
|
|
288
295
|
Not every resource supports every operation.
|
|
289
296
|
|
|
297
|
+
Use `isinstance` or `issubclass` with `GetExchange`, `GetQueue`, `GetStream`,
|
|
298
|
+
or `GetConsumer` to check whether a connection provides `exchange()`, `queue()`,
|
|
299
|
+
`stream()`, or `consumer()`, respectively. Import these contracts from `DefStream.Broker`.
|
|
300
|
+
|
|
290
301
|
| Method | Purpose | Timeout unit |
|
|
291
302
|
| --- | --- | --- |
|
|
292
303
|
| `send(body)` | Publish a message | Adapter configuration |
|
|
@@ -561,6 +572,11 @@ Inspector has no built-in TLS and is not a public web server.
|
|
|
561
572
|
The console's connection factory must return a new connection on every call,
|
|
562
573
|
never the Worker's connection.
|
|
563
574
|
|
|
575
|
+
Console's `broker` parameter uses the `DefStream.Broker.BrokerFactory` contract.
|
|
576
|
+
Its `__call__() -> Connection` takes no arguments and returns a new connection.
|
|
577
|
+
Functions such as `create_connection` above and lambdas remain valid without changes.
|
|
578
|
+
For a class-based factory, you can inherit `BrokerFactory` and implement `__call__`.
|
|
579
|
+
|
|
564
580
|
## Broker selection and operational considerations
|
|
565
581
|
|
|
566
582
|
| Feature | RabbitMQ | Redis Streams |
|
|
@@ -148,7 +148,7 @@ Worker가 실행 중인 상태에서 다른 터미널에서 실행하세요.
|
|
|
148
148
|
|
|
149
149
|
```python
|
|
150
150
|
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection
|
|
151
|
-
from DefStream.Worker import
|
|
151
|
+
from DefStream.Worker import emit, request
|
|
152
152
|
from tasks import Add
|
|
153
153
|
|
|
154
154
|
|
|
@@ -160,7 +160,7 @@ connection = Connection(Configuration(
|
|
|
160
160
|
))
|
|
161
161
|
try:
|
|
162
162
|
connection.connect()
|
|
163
|
-
message_id =
|
|
163
|
+
message_id = emit(
|
|
164
164
|
{'a': 10, 'b': 20},
|
|
165
165
|
task=Add,
|
|
166
166
|
broker=connection,
|
|
@@ -181,7 +181,7 @@ finally:
|
|
|
181
181
|
python client.py
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
-
`
|
|
184
|
+
`emit()`와 `request()`는 **각각 별도의 작업을 발행**합니다. 위 예제는 덧셈을 두 번 실행하며,
|
|
185
185
|
`request()`의 결과는 `30`입니다. `request()`의 제한 시간은 초 단위이고,
|
|
186
186
|
시간이 초과되어도 이미 전달된 작업은 취소되지 않습니다.
|
|
187
187
|
|
|
@@ -192,14 +192,20 @@ python client.py
|
|
|
192
192
|
| 함수 | 역할 | 연결 관리 |
|
|
193
193
|
| --- | --- | --- |
|
|
194
194
|
| `declare(task=..., broker=...)` | 작업의 큐·구독 리소스 선언 | 호출자가 연결·종료 |
|
|
195
|
-
| `
|
|
195
|
+
| `emit(body, task=..., broker=...)` | 작업 목적지로 단방향 메시지 발행 | 호출자가 연결·종료 |
|
|
196
196
|
| `request(body, task=..., broker=..., timeout=5)` | 작업 결과를 동기 RPC로 요청 | 호출자가 연결·종료; RabbitMQ만 지원 |
|
|
197
197
|
|
|
198
198
|
세 함수는 `DefStream.Worker`에서 가져옵니다. 전달된 연결을 자동으로 열거나 닫지 않으며,
|
|
199
|
-
`
|
|
199
|
+
`emit()`와 `request()`는 목적지를 자동 선언하지 않습니다.
|
|
200
200
|
수신 Worker 또는 별도의 준비 단계에서 먼저 `declare()`를 호출하세요.
|
|
201
201
|
하나의 연결을 같은 소유 스레드에서 여러 발행에 재사용할 수 있습니다.
|
|
202
202
|
|
|
203
|
+
세 함수 모두 공통 `Connection`을 받고, 내부에서 선언·발행·RPC 지원 여부를 확인합니다.
|
|
204
|
+
지원하지 않는 기능은 `NotImplementedError`로 실패합니다.
|
|
205
|
+
기존 작업 발행 함수와 연결의 `send`는 `emit`으로 이름이 바뀌었습니다.
|
|
206
|
+
사용자 정의 브로커의 작업 발행 계약도 `TaskSender.send` 대신 `Emittable.emit`을 사용하세요.
|
|
207
|
+
큐·Exchange·Stream의 저수준 `Sendable.send()`와 RPC `Callable.call()`은 그대로입니다.
|
|
208
|
+
|
|
203
209
|
작업 본문은 **문자열 키를 가진 매핑**이어야 하며, 반환값은 어댑터가 직렬화할 수 있어야 합니다.
|
|
204
210
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
205
211
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
@@ -217,7 +223,7 @@ from DefStream.Worker import (
|
|
|
217
223
|
Run,
|
|
218
224
|
declare,
|
|
219
225
|
request,
|
|
220
|
-
|
|
226
|
+
emit,
|
|
221
227
|
)
|
|
222
228
|
|
|
223
229
|
|
|
@@ -242,7 +248,7 @@ declare(
|
|
|
242
248
|
task=Add,
|
|
243
249
|
broker=broker,
|
|
244
250
|
)
|
|
245
|
-
|
|
251
|
+
emit(
|
|
246
252
|
{'a': 10, 'b': 20},
|
|
247
253
|
task=Add,
|
|
248
254
|
broker=broker,
|
|
@@ -282,6 +288,10 @@ result = request(
|
|
|
282
288
|
브로커 리소스를 직접 사용할 때의 공통 메서드는 다음과 같습니다.
|
|
283
289
|
모든 리소스가 모든 메서드를 지원하는 것은 아닙니다.
|
|
284
290
|
|
|
291
|
+
연결의 `exchange()`·`queue()`·`stream()`·`consumer()` 지원 여부는 각각
|
|
292
|
+
`GetExchange`·`GetQueue`·`GetStream`·`GetConsumer`로 `isinstance` 또는 `issubclass`
|
|
293
|
+
검사할 수 있습니다. 이 계약들은 `DefStream.Broker`에서 가져옵니다.
|
|
294
|
+
|
|
285
295
|
| 메서드 | 의미 | 제한 시간 단위 |
|
|
286
296
|
| --- | --- | --- |
|
|
287
297
|
| `send(body)` | 메시지 발행 | 어댑터별 설정 |
|
|
@@ -546,6 +556,11 @@ inspector = Inspector(
|
|
|
546
556
|
Inspector 자체는 TLS를 제공하지 않으며 공개 웹 서버가 아닙니다.
|
|
547
557
|
콘솔의 연결 팩터리는 호출마다 새 연결을 반환해야 하고 Worker 연결을 공유하면 안 됩니다.
|
|
548
558
|
|
|
559
|
+
Console의 `broker` 인자는 `DefStream.Broker.BrokerFactory` 계약을 사용합니다.
|
|
560
|
+
이 계약의 `__call__() -> Connection`은 인자 없이 새 연결을 반환합니다.
|
|
561
|
+
위의 `create_connection` 같은 함수나 람다도 그대로 전달할 수 있으며,
|
|
562
|
+
클래스로 구현할 때는 `BrokerFactory`를 상속하고 `__call__`을 구현할 수 있습니다.
|
|
563
|
+
|
|
549
564
|
## 브로커 선택과 운영 주의사항
|
|
550
565
|
|
|
551
566
|
| 기능 | RabbitMQ | Redis Streams |
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## 변경 후 (TO-BE)
|
|
9
9
|
|
|
10
|
-
지원 브로커의 작업 구독 설정에 기본·최대 우선순위를 정의하고, `
|
|
10
|
+
지원 브로커의 작업 구독 설정에 기본·최대 우선순위를 정의하고, `emit`과 `request`에서
|
|
11
11
|
메시지별 우선순위를 재정의할 수 있습니다. 현재 지원 브로커는 RabbitMQ입니다.
|
|
12
12
|
|
|
13
13
|
## 사용 방법
|
|
@@ -20,7 +20,7 @@ RabbitMQ 작업의 `parameters`에 `Subscription(priority=2, max_priority=5, ...
|
|
|
20
20
|
from DefStream.Worker import (
|
|
21
21
|
declare,
|
|
22
22
|
request,
|
|
23
|
-
|
|
23
|
+
emit,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
|
|
@@ -31,7 +31,7 @@ declare(
|
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
# 호출값을 생략하면 작업 구독의 기본 우선순위를 사용합니다.
|
|
34
|
-
|
|
34
|
+
emit(
|
|
35
35
|
{'a': 1, 'b': 2},
|
|
36
36
|
task=Add,
|
|
37
37
|
broker=broker,
|
|
@@ -131,3 +131,102 @@ RabbitMQ 선택적 통합 테스트는 활성화되어 실제 서버에 접속
|
|
|
131
131
|
`WorkerConnection`을 직접 import하거나 타입 힌트에 쓰던 코드는
|
|
132
132
|
`from DefStream.Broker import Connection`으로 변경해야 한다.
|
|
133
133
|
컨슈머 없는 연결은 워커 생성 시점이 아니라 실행 중 컨슈머 생성 직전에 거부된다.
|
|
134
|
+
|
|
135
|
+
## 7. 기능별 연결 검사와 작업 발행 이름 통일
|
|
136
|
+
|
|
137
|
+
추가 요구사항에 따라 다음을 반영했다.
|
|
138
|
+
|
|
139
|
+
- `GetExchange`, `GetQueue`, `GetStream`에 `@runtime_checkable`을 추가했다.
|
|
140
|
+
- `TaskSender`를 `Emittable`로, `send` 작업 도우미와 브로커 메서드를 `emit`으로
|
|
141
|
+
변경했다. 공개 export·우선순위 계약·RabbitMQ·Redis 어댑터도 함께 변경했다.
|
|
142
|
+
기존 이름의 호환 별칭은 제공하지 않는다.
|
|
143
|
+
- `declare`, `emit`, `request`의 입력을 모두 `broker: Connection`으로 통일했다.
|
|
144
|
+
내부에서 각각 `Declarable`, `Emittable`, `Requestable`을 검사한다.
|
|
145
|
+
- `request`의 잘못된 `TaskSender` 타입을 제거하고 RPC만 가능한 연결도 지원한다.
|
|
146
|
+
RPC 지원 검사는 우선순위 처리 전에 수행한다.
|
|
147
|
+
- `PrioritySupport`는 이미 제공하던 발행·RPC 계약을 상속 관계로도 표현하도록
|
|
148
|
+
`Emittable`, `Requestable`을 상속한다. 선택적 `priority` 인자를 정적 분석에서도
|
|
149
|
+
올바르게 해석하게 하며, RabbitMQ는 중복 상속을 제거했다.
|
|
150
|
+
- Inspector Console의 별도 `Producer` 합성 타입을 제거하고 팩터리가
|
|
151
|
+
`Connection`을 반환하도록 변경했다. 내부 발행은 `emit`을 사용하지만
|
|
152
|
+
HTTP의 `mode="send"`와 기존 화면은 유지했다.
|
|
153
|
+
- 저수준 `Sendable.send()`·`Callable.call()`은 유지한다.
|
|
154
|
+
- 관련 테스트와 예제, 코어·어댑터의 한영 README 및 연결된 사용 예제를 갱신했다.
|
|
155
|
+
|
|
156
|
+
### 추가 검증 결과
|
|
157
|
+
|
|
158
|
+
현재 소스를 직접 로드하는 동일한 검증 방식으로 Docker `defstream-rabbitmq`를
|
|
159
|
+
재시작하고 `DEFSTREAM_RABBITMQ_TESTS=1`로 실행했다.
|
|
160
|
+
|
|
161
|
+
| 대상 | 전체 | 통과 | 건너뜀 | 실패·오류 |
|
|
162
|
+
|---|---:|---:|---:|---:|
|
|
163
|
+
| 코어 | 164 | 160 | 4 | 0 |
|
|
164
|
+
| RabbitMQ 어댑터 | 60 | 60 | 0 | 0 |
|
|
165
|
+
| Redis 어댑터 | 36 | 32 | 4 | 0 |
|
|
166
|
+
| 합계 | 260 | 252 | 8 | 0 |
|
|
167
|
+
|
|
168
|
+
- 건너뛴 8개는 Redis 실서버 전용 테스트이다. Redis 실제 서버 테스트는 실행하지 않았다.
|
|
169
|
+
- 생성자와 도우미 타입, 기능별 지원·거부, RPC 전용 연결, `emit` 공개 이름과
|
|
170
|
+
기존 작업 `send` 제거, 런타임 Protocol 검사를 검증했다.
|
|
171
|
+
- 기존 우선순위 테스트와 실제 RabbitMQ 발행·RPC·소비·실패 처리·Inspector가 통과했다.
|
|
172
|
+
- `Message.py`, `Broker/Connection.py`와 양쪽 공개 export는 Pylance 오류가 없었다.
|
|
173
|
+
Console에는 기존 미사용 매개변수 안내만 남아 있다.
|
|
174
|
+
- Pylance가 해석한 `emit` 호출 위치는 시그니처와 호환됐다.
|
|
175
|
+
테스트 도구에서는 테스트를 찾지 못해 기존 `unittest`로 검증했다.
|
|
176
|
+
- 검증 후 테스트용 RabbitMQ를 종료하고 재사용 가능한 컨테이너는 보존했다.
|
|
177
|
+
|
|
178
|
+
## 8. Redis·RabbitMQ 동시 실서버 검증
|
|
179
|
+
|
|
180
|
+
2026-10-19에 Redis 전용 Docker 컨테이너를 추가하고, 이전에 건너뛴 Redis
|
|
181
|
+
통합 테스트까지 모두 실행했다. 위의 Redis 미검증 기록은 이 재검증 이전 결과이다.
|
|
182
|
+
|
|
183
|
+
- 컨테이너: `defstream-redis`, 이미지: `redis:7`, 실제 Redis 버전: `7.4.11`.
|
|
184
|
+
- 포트는 `127.0.0.1:6379`에만 공개했고 `redis-cli ping`의 `PONG`을 확인했다.
|
|
185
|
+
- `defstream-rabbitmq`도 다시 시작하고 `rabbitmq-diagnostics -q ping`을 확인했다.
|
|
186
|
+
- `DEFSTREAM_REDIS_TESTS=1`과 `DEFSTREAM_RABBITMQ_TESTS=1`을 동시에 설정했다.
|
|
187
|
+
- 가상환경에 설치된 이전 패키지가 아니라 현재 코어·어댑터 소스를 직접 로드해
|
|
188
|
+
각 프로젝트의 전체 `unittest`를 별도 Python 프로세스에서 실행했다.
|
|
189
|
+
|
|
190
|
+
```powershell
|
|
191
|
+
docker run -d --name defstream-redis -p 127.0.0.1:6379:6379 redis:7
|
|
192
|
+
docker exec defstream-redis redis-cli ping
|
|
193
|
+
docker start defstream-rabbitmq
|
|
194
|
+
docker exec defstream-rabbitmq rabbitmq-diagnostics -q ping
|
|
195
|
+
$env:DEFSTREAM_REDIS_TESTS = '1'
|
|
196
|
+
$env:DEFSTREAM_RABBITMQ_TESTS = '1'
|
|
197
|
+
$env:PYTHONIOENCODING = 'utf-8'
|
|
198
|
+
$env:PYTHONUTF8 = '1'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| 대상 | 전체 | 통과 | 건너뜀 | 실패·오류 | 소요 시간 |
|
|
202
|
+
|---|---:|---:|---:|---:|---:|
|
|
203
|
+
| 코어 | 164 | 164 | 0 | 0 | 32.319초 |
|
|
204
|
+
| RabbitMQ 어댑터 | 60 | 60 | 0 | 0 | 5.546초 |
|
|
205
|
+
| Redis 어댑터 | 36 | 36 | 0 | 0 | 2.198초 |
|
|
206
|
+
| 합계 | 260 | 260 | 0 | 0 | 40.063초 |
|
|
207
|
+
|
|
208
|
+
Redis의 발행·소비·이력 읽기·원자적 재전달, QoS·콜백·정상 종료, 방치된 pending
|
|
209
|
+
회수와 실행 풀 연동을 검증했다. 코어의 Redis 발행·완료 훅·Inspector 상태·메트릭·Console
|
|
210
|
+
통합 테스트도 통과했다. RabbitMQ 통합 테스트 역시 활성화된 상태로 통과했다.
|
|
211
|
+
|
|
212
|
+
검증 후 Redis `DBSIZE`가 `0`임을 확인했다. 두 컨테이너 모두 종료했고
|
|
213
|
+
`exited`, `running=false` 상태를 확인했다. 컨테이너는 보존하여
|
|
214
|
+
`docker start defstream-redis defstream-rabbitmq`로 재사용할 수 있다.
|
|
215
|
+
|
|
216
|
+
## 9. 브로커 팩터리 계약 명명
|
|
217
|
+
|
|
218
|
+
- `Broker/Connection.py`에 `BrokerFactory` Protocol을 정의하고
|
|
219
|
+
`DefStream.Broker`에서 공개했다.
|
|
220
|
+
- `__call__(self) -> Connection`으로 인자 없는 새 연결 생성 계약을 명시했다.
|
|
221
|
+
독립적인 연결을 매번 반환해야 한다는 책임을 독스트링에 기록했다.
|
|
222
|
+
- Console의 `broker` 타입을 `Callable[[], Connection]`에서 `BrokerFactory`로
|
|
223
|
+
변경했다. 기존 `callable` 검사와 연결 생성·종료 흐름은 변경하지 않았다.
|
|
224
|
+
- 함수·람다·명시적 상속 클래스·구조적 호출 클래스 모두 사용할 수 있도록 유지했다.
|
|
225
|
+
- 타입 힌트, 공개 export, 불완전한 구현의 인스턴스화 거부, 네 가지 팩터리 형태와
|
|
226
|
+
호출마다 서로 다른 연결을 반환하는 동작을 테스트했다.
|
|
227
|
+
- 한영 README와 사용자용 변경 로그에 계약과 기존 코드 호환성을 설명했다.
|
|
228
|
+
- 현재 소스를 직접 로드해 계약·Console 테스트 31개 중 29개 통과,
|
|
229
|
+
실서버 전용 2개 건너뜀을 확인했다. 이번 타입 명명 변경에서는 Docker 실서버
|
|
230
|
+
테스트를 재실행하지 않았으며, 이전 260개 실서버 검증과 구분한다.
|
|
231
|
+
- `Broker/Connection.py`의 Pylance 진단에 오류가 없었다.
|
|
232
|
+
Console에는 기존 미사용 매개변수 안내만 남아 있다.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 워커에 공통 브로커 연결 타입 사용
|
|
2
|
+
|
|
3
|
+
## 달라진 점
|
|
4
|
+
|
|
5
|
+
이전에는 워커에 전달할 연결의 타입을 표시하려면 워커 전용 `WorkerConnection`을
|
|
6
|
+
사용해야 했습니다. 이제 `DefStream.Broker.Connection`을 사용하면 됩니다.
|
|
7
|
+
워커를 위해 별도의 연결 타입을 가져오거나 정의할 필요가 없습니다.
|
|
8
|
+
|
|
9
|
+
RabbitMQ·Redis 연결 객체를 `Worker`에 전달하는 기존 코드는 그대로 사용할 수 있습니다.
|
|
10
|
+
메시지 처리, ACK/NACK, 실패 정책, RPC와 스레드·프로세스 풀의 동작도 동일합니다.
|
|
11
|
+
|
|
12
|
+
## 기존 코드에서 바꿀 부분
|
|
13
|
+
|
|
14
|
+
`WorkerConnection`을 직접 가져오거나 타입 힌트에 사용했다면 공통 `Connection`으로
|
|
15
|
+
변경하세요. `WorkerConnection`은 더 이상 제공하지 않습니다.
|
|
16
|
+
|
|
17
|
+
변경 전:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from DefStream.Worker import WorkerConnection
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
변경 후:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from DefStream.Broker import Connection
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
해당 타입을 사용한 매개변수·반환값·변수의 타입 힌트도 `Connection`으로 바꾸면 됩니다.
|
|
30
|
+
브로커 객체만 전달하고 있었다면 수정할 필요가 없습니다.
|
|
31
|
+
|
|
32
|
+
## 직접 만든 브로커를 사용하는 경우
|
|
33
|
+
|
|
34
|
+
워커에서 사용할 연결에는 `connect()`, `close()` 외에 컨슈머를 만드는 `consumer()`가
|
|
35
|
+
있어야 합니다. 호출자가 별도로 검사하거나 워커 전용 타입을 상속할 필요는 없습니다.
|
|
36
|
+
|
|
37
|
+
워커가 연결과 setup을 마친 뒤 `consumer()` 지원 여부를 확인합니다.
|
|
38
|
+
지원하지 않으면 `TypeError: Worker broker must support consumer creation`으로
|
|
39
|
+
실패하고 종료 처리를 수행합니다. 메시지 발행만 가능한 연결은 워커에 사용할 수 없습니다.
|
|
40
|
+
|
|
41
|
+
공통 `Connection` 자체에는 `consumer()` 구현을 강제하지 않으므로,
|
|
42
|
+
워커에 사용하지 않는 발행 전용 연결은 변경할 필요가 없습니다.
|
|
43
|
+
|
|
44
|
+
## 작업 발행은 `emit` 사용
|
|
45
|
+
|
|
46
|
+
작업을 보내는 함수와 브로커 연결 메서드의 이름이 `send`에서 `emit`으로 바뀌었습니다.
|
|
47
|
+
코어와 RabbitMQ·Redis 어댑터를 함께 갱신하세요. 이전 이름은 더 이상 제공하지 않습니다.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from DefStream.Worker import emit
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# broker는 호출자가 연결한 브로커이며, Add는 기존 작업 클래스입니다.
|
|
54
|
+
emit(
|
|
55
|
+
{'a': 10, 'b': 20},
|
|
56
|
+
task=Add,
|
|
57
|
+
broker=broker,
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
직접 `connection.send(body, parameters)`를 호출했다면
|
|
62
|
+
`connection.emit(body, parameters)`로 바꾸세요.
|
|
63
|
+
큐·Exchange·Stream을 직접 사용하는 `send(body)`와 RPC `call(body)`는 바뀌지 않습니다.
|
|
64
|
+
|
|
65
|
+
`declare`, `emit`, `request` 모두 공통 `Connection`을 받습니다.
|
|
66
|
+
사용하는 쪽에서 기능별 연결 타입을 따로 지정할 필요가 없으며,
|
|
67
|
+
지원하지 않는 기능을 호출하면 `NotImplementedError`가 발생합니다.
|
|
68
|
+
이 함수들은 여전히 연결을 자동으로 열거나 닫지 않습니다.
|
|
69
|
+
|
|
70
|
+
사용자 정의 브로커에서 `TaskSender`를 사용했다면 `DefStream.Broker.Emittable`을
|
|
71
|
+
가져오고 작업 발행 메서드 이름을 `emit`으로 변경하세요.
|
|
72
|
+
선언과 RPC의 계약인 `Declarable.declare`와 `Requestable.request`는 유지됩니다.
|
|
73
|
+
|
|
74
|
+
## 연결 기능 지원 여부 확인
|
|
75
|
+
|
|
76
|
+
`GetExchange`, `GetQueue`, `GetStream`도 `GetConsumer`처럼 런타임 검사를 지원합니다.
|
|
77
|
+
예를 들어 `isinstance(connection, GetQueue)` 또는
|
|
78
|
+
`issubclass(ConnectionClass, GetQueue)`로 큐 생성 기능의 지원 여부를 확인할 수 있습니다.
|
|
79
|
+
각 계약은 `DefStream.Broker`에서 가져옵니다.
|
|
80
|
+
|
|
81
|
+
## 브로커 연결 팩터리 타입
|
|
82
|
+
|
|
83
|
+
Console에 전달하는 연결 생성 함수의 타입을 `BrokerFactory`라는 이름으로 제공합니다.
|
|
84
|
+
`from DefStream.Broker import BrokerFactory`로 가져올 수 있으며,
|
|
85
|
+
인자 없는 `__call__()`이 새 `Connection`을 반환하는 계약입니다.
|
|
86
|
+
|
|
87
|
+
기존 함수나 람다를 전달하는 코드는 바꾸지 않아도 됩니다.
|
|
88
|
+
클래스로 팩터리를 구현하려면 `BrokerFactory`를 상속하고 `__call__()`을 구현할 수 있습니다.
|
|
89
|
+
호출마다 새 연결을 반환해야 하며 Worker의 연결을 재사용하면 안 됩니다.
|
|
90
|
+
|
|
91
|
+
## 상세 기록
|
|
92
|
+
|
|
93
|
+
- [요구사항 명세서](./REQUIREMENTS.md)
|
|
94
|
+
- [구현 및 RabbitMQ 검증 기록](./IMPLEMENTS.md)
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
## 4. 범위와 제한
|
|
35
35
|
|
|
36
36
|
- 변경 대상은 코어의 연결 계약, 워커, 직접 관련된 테스트와 문서이다.
|
|
37
|
-
- RabbitMQ·Redis
|
|
37
|
+
- RabbitMQ·Redis 어댑터는 아래 추가 요구사항에 따라 작업 발행 이름을 함께 변경한다.
|
|
38
38
|
- 사용자 정의 연결에 `GetConsumer`의 명시적 상속을 강제하지 않는다.
|
|
39
39
|
- 런타임 Protocol 검사는 기능의 구조적 지원 여부를 확인한다.
|
|
40
40
|
메서드 매개변수·반환 타입이나 실제 실행 성공까지 검증하는 기능은 아니다.
|
|
@@ -50,3 +50,29 @@
|
|
|
50
50
|
| WCAT-04 | 기존 워커 수명 주기, setup·cleanup, 스레드·프로세스 실행 테스트가 통과한다. |
|
|
51
51
|
| WCAT-05 | Docker의 `defstream-rabbitmq`를 사용하여 실제 소비·재전달·거부·종료, RPC, Inspector 연동을 검증한다. RabbitMQ 테스트를 건너뛴 결과를 실서버 검증으로 간주하지 않는다. |
|
|
52
52
|
| WCAT-06 | 설치된 과거 패키지가 아니라 현재 브랜치의 코어 소스와 로컬 RabbitMQ 어댑터를 로드해 검증한다. |
|
|
53
|
+
|
|
54
|
+
## 6. 연결 기능 검사와 작업 발행 이름 추가 요구사항
|
|
55
|
+
|
|
56
|
+
- `GetExchange`, `GetQueue`, `GetStream`에도 `@runtime_checkable`을 적용한다.
|
|
57
|
+
- `TaskSender`는 `Emittable`로, 작업 발행 메서드와 워커 도우미 `send`는
|
|
58
|
+
`emit`으로 변경한다. 기존 이름의 호환 별칭은 추가하지 않는다.
|
|
59
|
+
- `declare`, `emit`, `request`는 모두 `broker: Connection`을 받고 내부에서
|
|
60
|
+
각각 `Declarable`, `Emittable`, `Requestable`을 검사한다.
|
|
61
|
+
- 미지원 기능은 기존 방식의 `NotImplementedError`로 명시적으로 실패한다.
|
|
62
|
+
RPC 검사는 우선순위 유무와 무관하게 수행한다.
|
|
63
|
+
- 우선순위 기능 계약과 RabbitMQ·Redis 구현체의 작업 발행 이름도 `emit`으로 맞춘다.
|
|
64
|
+
- 큐·Exchange·Stream의 저수준 `Sendable.send()`와 `Callable.call()`은 유지한다.
|
|
65
|
+
- Inspector Console의 브로커 팩터리도 공통 `Connection`을 반환하도록 단순화한다.
|
|
66
|
+
기존 HTTP `mode="send"`와 화면 동작은 유지하고 내부 호출만 `emit`으로 바꾼다.
|
|
67
|
+
- 테스트, 예제, 한영 사용 설명서 및 각 프로젝트 현재 브랜치 문서를 갱신한다.
|
|
68
|
+
- 생성자와 도우미 타입 힌트, 기능별 성공·실패, 우선순위, 실제 RabbitMQ 연동과
|
|
69
|
+
Redis 회귀 테스트로 검증한다.
|
|
70
|
+
|
|
71
|
+
## 7. 브로커 팩터리 계약
|
|
72
|
+
|
|
73
|
+
- 공통 브로커에 `BrokerFactory` Protocol을 공개하며 `__call__(self) -> Connection`을 정의한다.
|
|
74
|
+
- Console의 `broker` 입력 타입은 `Callable[[], Connection]` 대신 `BrokerFactory`를 사용한다.
|
|
75
|
+
- 기존 함수·람다와 호출 가능한 클래스도 구조적으로 사용할 수 있어야 한다.
|
|
76
|
+
명시적 상속이나 어댑터를 호출자에게 강제하지 않는다.
|
|
77
|
+
- 호출마다 독립적인 새 연결을 반환하는 계약을 문서화한다.
|
|
78
|
+
Console의 기존 호출 가능 여부 검사와 연결 생성·종료 동작은 유지한다.
|