DefStream 0.1.3.7__tar.gz → 0.1.4.12__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.3.7 → defstream-0.1.4.12}/.github/workflows/ci.yml +111 -5
- {defstream-0.1.3.7 → defstream-0.1.4.12}/DefStream.egg-info/PKG-INFO +66 -1
- {defstream-0.1.3.7 → defstream-0.1.4.12}/DefStream.egg-info/SOURCES.txt +7 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/PKG-INFO +66 -1
- {defstream-0.1.3.7 → defstream-0.1.4.12}/README.en.md +67 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/README.md +65 -0
- defstream-0.1.4.12/issues/feature/1/IMPLEMENTS.md +73 -0
- defstream-0.1.4.12/issues/feature/1/README.md +74 -0
- defstream-0.1.4.12/issues/feature/1/REQUIREMENTS.md +134 -0
- defstream-0.1.4.12/issues/feature/1/TASK.md +40 -0
- defstream-0.1.4.12/issues/feature/1/ci.refs.json +4 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Connection.py +28 -0
- defstream-0.1.4.12/src/Broker/Priority.py +26 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/__init__.py +10 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Message.py +78 -2
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Run.py +51 -0
- defstream-0.1.4.12/test/test_task_priorities.py +396 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/.gitignore +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/DefStream.egg-info/dependency_links.txt +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/DefStream.egg-info/requires.txt +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/DefStream.egg-info/top_level.txt +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/LICENSE +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Broker/Sample.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Worker/RabbitMQ/Client.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Worker/RabbitMQ/Tasks.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Worker/RabbitMQ/Worker.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Worker/Redis/Sample.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/sample/Worker/Sample.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/setup.cfg +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/setup.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Configuration.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Consumer.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Errors.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Event.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Implements/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Policies.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Broker/Protocol.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Descriptor/DataObject.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Descriptor/Types.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Descriptor/Value.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Descriptor/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extension.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Console.html +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Console.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Dashboard.html +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Dashboard.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/HealthCheck.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Metrics.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/Specifications.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Extensions/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Inspector.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/Response.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Inspector/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Pattern.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Array.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Common.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Compare.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Condition.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/DataObject.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/DateTime.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Number.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Object.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Size.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/String.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/Type.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Patterns/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Validate.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/Validator.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Validator/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Executor.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Pool.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Specification.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Startup.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/Worker.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/Worker/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/src/__init__.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_dashboard.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_dashboard_ui.cjs +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_inspector.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_inspector_console.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_lifecycle_hooks.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_pool_callbacks.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_process_signals.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_protocol_contracts.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_runner_hooks.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_specifications.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_task_messages.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_worker.py +0 -0
- {defstream-0.1.3.7 → defstream-0.1.4.12}/test/test_worker_startup.py +0 -0
|
@@ -19,11 +19,17 @@ concurrency:
|
|
|
19
19
|
jobs:
|
|
20
20
|
changes:
|
|
21
21
|
name: Plan release version
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
pull-requests: read
|
|
22
25
|
runs-on: ubuntu-latest
|
|
23
26
|
timeout-minutes: 5
|
|
24
27
|
outputs:
|
|
25
28
|
release: ${{ steps.changes.outputs.release }}
|
|
26
29
|
version: ${{ steps.changes.outputs.version }}
|
|
30
|
+
core_ref: ${{ steps.refs.outputs.core_ref }}
|
|
31
|
+
rabbitmq_ref: ${{ steps.refs.outputs.rabbitmq_ref }}
|
|
32
|
+
redis_ref: ${{ steps.refs.outputs.redis_ref }}
|
|
27
33
|
steps:
|
|
28
34
|
- uses: actions/checkout@v7
|
|
29
35
|
with:
|
|
@@ -33,6 +39,96 @@ jobs:
|
|
|
33
39
|
uses: actions/setup-python@v7
|
|
34
40
|
with:
|
|
35
41
|
python-version: '3.13'
|
|
42
|
+
- name: Validate PR branch changelog
|
|
43
|
+
id: changelog
|
|
44
|
+
env:
|
|
45
|
+
GH_TOKEN: ${{ github.token }}
|
|
46
|
+
run: |
|
|
47
|
+
python - <<'PY'
|
|
48
|
+
from json import loads
|
|
49
|
+
from os import environ
|
|
50
|
+
from pathlib import Path
|
|
51
|
+
from subprocess import check_output
|
|
52
|
+
|
|
53
|
+
head = environ['GITHUB_SHA']
|
|
54
|
+
if environ['GITHUB_EVENT_NAME'] == 'pull_request':
|
|
55
|
+
event = loads(Path(environ['GITHUB_EVENT_PATH']).read_text(encoding='utf-8'))
|
|
56
|
+
branch = event['pull_request']['head']['ref']
|
|
57
|
+
else:
|
|
58
|
+
repository = environ['GITHUB_REPOSITORY']
|
|
59
|
+
pages = loads(check_output([
|
|
60
|
+
'gh', 'api', '--paginate', '--slurp',
|
|
61
|
+
f'repos/{repository}/commits/{head}/pulls?per_page=100',
|
|
62
|
+
]))
|
|
63
|
+
pulls = [
|
|
64
|
+
pull for page in pages for pull in page
|
|
65
|
+
if pull['merged_at'] is not None
|
|
66
|
+
and pull['merge_commit_sha'] == head
|
|
67
|
+
and pull['base']['ref'] == 'master'
|
|
68
|
+
and pull['base']['repo']['full_name'] == repository
|
|
69
|
+
]
|
|
70
|
+
if len(pulls) != 1:
|
|
71
|
+
raise ValueError('Expected exactly one merged PR for the release commit')
|
|
72
|
+
branch = pulls[0]['head']['ref']
|
|
73
|
+
path = f'issues/{branch}/README.md'
|
|
74
|
+
entry = check_output(['git', 'ls-tree', head, '--', path]).decode().split()
|
|
75
|
+
if not entry or entry[0] not in ('100644', '100755'):
|
|
76
|
+
raise ValueError(f'Changelog must exist as a regular file: {path}')
|
|
77
|
+
body = check_output(['git', 'show', f'{head}:{path}'])
|
|
78
|
+
if not body.decode('utf-8').strip():
|
|
79
|
+
raise ValueError(f'Customer changelog is empty: {path}')
|
|
80
|
+
notes = Path(environ['RUNNER_TEMP'], 'release-notes', 'README.md')
|
|
81
|
+
notes.parent.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
notes.write_bytes(body)
|
|
83
|
+
print(f'Customer changelog: {path}')
|
|
84
|
+
with Path(environ['GITHUB_OUTPUT']).open('a', encoding='utf-8') as output:
|
|
85
|
+
output.write(f'branch={branch}\n')
|
|
86
|
+
PY
|
|
87
|
+
- name: Resolve dependency refs
|
|
88
|
+
id: refs
|
|
89
|
+
env:
|
|
90
|
+
BRANCH: ${{ steps.changelog.outputs.branch }}
|
|
91
|
+
run: |
|
|
92
|
+
python - <<'PY'
|
|
93
|
+
from json import loads
|
|
94
|
+
from os import environ
|
|
95
|
+
from pathlib import Path
|
|
96
|
+
from subprocess import check_output, run
|
|
97
|
+
|
|
98
|
+
head = environ['GITHUB_SHA']
|
|
99
|
+
path = f'issues/{environ["BRANCH"]}/ci.refs.json'
|
|
100
|
+
entry = check_output(['git', 'ls-tree', head, '--', path]).decode().split()
|
|
101
|
+
refs = {}
|
|
102
|
+
if entry:
|
|
103
|
+
if entry[0] not in ('100644', '100755'):
|
|
104
|
+
raise ValueError(f'Dependency refs must be a regular file: {path}')
|
|
105
|
+
refs = loads(check_output(['git', 'show', f'{head}:{path}']).decode('utf-8'))
|
|
106
|
+
else:
|
|
107
|
+
print(f'{path} not found: dependency refs default to master')
|
|
108
|
+
projects = {
|
|
109
|
+
'DefStream': 'core_ref',
|
|
110
|
+
'DefStream-RabbitMQ': 'rabbitmq_ref',
|
|
111
|
+
'DefStream-Redis': 'redis_ref',
|
|
112
|
+
}
|
|
113
|
+
if not isinstance(refs, dict) or refs.keys() - projects.keys():
|
|
114
|
+
raise ValueError(f'Expected an object with only supported project names: {path}')
|
|
115
|
+
with Path(environ['GITHUB_OUTPUT']).open('a', encoding='utf-8') as output:
|
|
116
|
+
for project, key in projects.items():
|
|
117
|
+
ref = refs.get(project, 'master')
|
|
118
|
+
if not isinstance(ref, str) or not ref or ref.startswith('-'):
|
|
119
|
+
raise ValueError(f'Invalid dependency ref for {project}: {ref!r}')
|
|
120
|
+
run(['git', 'check-ref-format', '--allow-onelevel', ref], check=True)
|
|
121
|
+
output.write(f'{key}={ref}\n')
|
|
122
|
+
print(f'{project} dependency ref: {ref}')
|
|
123
|
+
PY
|
|
124
|
+
- name: Preserve customer release notes
|
|
125
|
+
uses: actions/upload-artifact@v7
|
|
126
|
+
with:
|
|
127
|
+
name: release-notes
|
|
128
|
+
path: ${{ runner.temp }}/release-notes/README.md
|
|
129
|
+
if-no-files-found: error
|
|
130
|
+
retention-days: 14
|
|
131
|
+
overwrite: true
|
|
36
132
|
- name: Check complete push range and plan version
|
|
37
133
|
id: changes
|
|
38
134
|
env:
|
|
@@ -132,7 +228,7 @@ jobs:
|
|
|
132
228
|
uses: actions/checkout@v7
|
|
133
229
|
with:
|
|
134
230
|
repository: yong5eon/DefStream
|
|
135
|
-
ref: ${{ github.event.repository.name == 'DefStream' && github.sha ||
|
|
231
|
+
ref: ${{ github.event.repository.name == 'DefStream' && github.sha || needs.changes.outputs.core_ref }}
|
|
136
232
|
path: packages/DefStream
|
|
137
233
|
fetch-depth: 0
|
|
138
234
|
persist-credentials: false
|
|
@@ -141,7 +237,7 @@ jobs:
|
|
|
141
237
|
uses: actions/checkout@v7
|
|
142
238
|
with:
|
|
143
239
|
repository: yong5eon/DefStream-RabbitMQ
|
|
144
|
-
ref: ${{ github.event.repository.name == 'DefStream-RabbitMQ' && github.sha ||
|
|
240
|
+
ref: ${{ github.event.repository.name == 'DefStream-RabbitMQ' && github.sha || needs.changes.outputs.rabbitmq_ref }}
|
|
145
241
|
path: packages/DefStream-RabbitMQ
|
|
146
242
|
fetch-depth: 0
|
|
147
243
|
persist-credentials: false
|
|
@@ -150,7 +246,7 @@ jobs:
|
|
|
150
246
|
uses: actions/checkout@v7
|
|
151
247
|
with:
|
|
152
248
|
repository: yong5eon/DefStream-Redis
|
|
153
|
-
ref: ${{ github.event.repository.name == 'DefStream-Redis' && github.sha ||
|
|
249
|
+
ref: ${{ github.event.repository.name == 'DefStream-Redis' && github.sha || needs.changes.outputs.redis_ref }}
|
|
154
250
|
path: packages/DefStream-Redis
|
|
155
251
|
fetch-depth: 0
|
|
156
252
|
persist-credentials: false
|
|
@@ -267,6 +363,12 @@ jobs:
|
|
|
267
363
|
name: distributions
|
|
268
364
|
path: dist
|
|
269
365
|
|
|
366
|
+
- name: Download customer release notes
|
|
367
|
+
uses: actions/download-artifact@v8
|
|
368
|
+
with:
|
|
369
|
+
name: release-notes
|
|
370
|
+
path: release-notes
|
|
371
|
+
|
|
270
372
|
- name: Set up Python
|
|
271
373
|
uses: actions/setup-python@v7
|
|
272
374
|
with:
|
|
@@ -371,6 +473,9 @@ jobs:
|
|
|
371
473
|
|
|
372
474
|
repository = environ['GITHUB_REPOSITORY']
|
|
373
475
|
version = environ['VERSION']
|
|
476
|
+
notes = Path('release-notes/README.md')
|
|
477
|
+
if not notes.read_text(encoding='utf-8').strip():
|
|
478
|
+
raise ValueError('Customer release notes are empty')
|
|
374
479
|
request = Request(
|
|
375
480
|
f'{environ["GITHUB_API_URL"]}/repos/{repository}/releases/tags/{quote(version, safe="")}',
|
|
376
481
|
headers={
|
|
@@ -387,7 +492,7 @@ jobs:
|
|
|
387
492
|
raise
|
|
388
493
|
run([
|
|
389
494
|
'gh', 'release', 'create', version, '--repo', repository,
|
|
390
|
-
'--verify-tag', '--title', version, '--
|
|
495
|
+
'--verify-tag', '--title', version, '--notes-file', str(notes), '--draft',
|
|
391
496
|
], check=True)
|
|
392
497
|
else:
|
|
393
498
|
if release['tag_name'] != version:
|
|
@@ -398,6 +503,7 @@ jobs:
|
|
|
398
503
|
'--clobber', *artifacts,
|
|
399
504
|
], check=True)
|
|
400
505
|
run([
|
|
401
|
-
'gh', 'release', 'edit', version, '--repo', repository,
|
|
506
|
+
'gh', 'release', 'edit', version, '--repo', repository,
|
|
507
|
+
'--notes-file', str(notes), '--draft=false',
|
|
402
508
|
], check=True)
|
|
403
509
|
PY
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4.12
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -232,6 +232,71 @@ python client.py
|
|
|
232
232
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
233
233
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
234
234
|
|
|
235
|
+
### 작업 우선순위
|
|
236
|
+
|
|
237
|
+
RabbitMQ classic 큐에서는 작업 `parameters`의 RabbitMQ `Subscription`에
|
|
238
|
+
`priority`로 기본 메시지 우선순위, `max_priority`로 큐 최대값을 함께 정의합니다.
|
|
239
|
+
`Run`에 별도의 `priority` 설정을 두지 않습니다.
|
|
240
|
+
`declare()`가 이 설정을 읽어 우선순위 큐를 준비합니다.
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from DefStream.Broker.Implements.RabbitMQ import Subscription
|
|
244
|
+
from DefStream.Worker import (
|
|
245
|
+
Run,
|
|
246
|
+
declare,
|
|
247
|
+
request,
|
|
248
|
+
send,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class Add(
|
|
253
|
+
Run,
|
|
254
|
+
parameters=Subscription(
|
|
255
|
+
queue='defstream.example.priority.add',
|
|
256
|
+
max_priority=5,
|
|
257
|
+
priority=2,
|
|
258
|
+
),
|
|
259
|
+
):
|
|
260
|
+
def run(
|
|
261
|
+
self,
|
|
262
|
+
a: int,
|
|
263
|
+
b: int,
|
|
264
|
+
):
|
|
265
|
+
return a + b
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# broker는 호출자가 연결한 RabbitMQ Connection입니다.
|
|
269
|
+
declare(
|
|
270
|
+
task=Add,
|
|
271
|
+
broker=broker,
|
|
272
|
+
)
|
|
273
|
+
send(
|
|
274
|
+
{'a': 10, 'b': 20},
|
|
275
|
+
task=Add,
|
|
276
|
+
broker=broker,
|
|
277
|
+
)
|
|
278
|
+
# RPC에는 별도로 실행 중인 Worker가 필요합니다.
|
|
279
|
+
result = request(
|
|
280
|
+
{'a': 10, 'b': 20},
|
|
281
|
+
task=Add,
|
|
282
|
+
broker=broker,
|
|
283
|
+
priority=5,
|
|
284
|
+
)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
- 호출의 `priority`가 생략되거나 `None`이면 작업 기본값을 사용합니다.
|
|
288
|
+
명시적 `0`은 가장 낮은 우선순위이며 기본값을 덮어씁니다.
|
|
289
|
+
- 작업 기본값만 지정하면 큐 최대값은 RabbitMQ 상한 `255`입니다.
|
|
290
|
+
최대값만 지정하면 기본값은 `None`이며, 호출값도 없으면 메시지 속성을 생략합니다.
|
|
291
|
+
- 작업 최대값을 초과하는 값, 음수, 정수가 아닌 값과 `bool`은 거부합니다.
|
|
292
|
+
- 작업 설정 없이 호출에서만 지정하면 브로커 범위 `0..255`만 검증합니다.
|
|
293
|
+
우선순위 큐의 사전 선언과 실제 큐 최대값 준수는 호출자 책임입니다.
|
|
294
|
+
- 자식 작업은 설정을 상속하고 유효한 값으로 재정의할 수 있지만 해제할 수는 없습니다.
|
|
295
|
+
- Redis에 우선순위를 요청하면 `NotImplementedError`가 발생합니다.
|
|
296
|
+
우선순위 미지정 시 기존 Redis 동작은 유지합니다.
|
|
297
|
+
- 우선순위는 같은 큐의 대기 메시지 전달에 적용됩니다. 이미 전달·실행 중인
|
|
298
|
+
작업을 선점하거나 여러 작업의 실행·완료 순서를 보장하지 않습니다.
|
|
299
|
+
|
|
235
300
|
### 성공, 실패와 재시도
|
|
236
301
|
|
|
237
302
|
- 작업 실행과 완료 훅이 성공한 뒤 ACK합니다. RabbitMQ RPC는 응답 발행도 ACK보다 먼저 수행합니다.
|
|
@@ -9,6 +9,11 @@ DefStream.egg-info/SOURCES.txt
|
|
|
9
9
|
DefStream.egg-info/dependency_links.txt
|
|
10
10
|
DefStream.egg-info/requires.txt
|
|
11
11
|
DefStream.egg-info/top_level.txt
|
|
12
|
+
issues/feature/1/IMPLEMENTS.md
|
|
13
|
+
issues/feature/1/README.md
|
|
14
|
+
issues/feature/1/REQUIREMENTS.md
|
|
15
|
+
issues/feature/1/TASK.md
|
|
16
|
+
issues/feature/1/ci.refs.json
|
|
12
17
|
sample/Broker/Sample.py
|
|
13
18
|
sample/Worker/Sample.py
|
|
14
19
|
sample/Worker/RabbitMQ/Client.py
|
|
@@ -22,6 +27,7 @@ src/Broker/Consumer.py
|
|
|
22
27
|
src/Broker/Errors.py
|
|
23
28
|
src/Broker/Event.py
|
|
24
29
|
src/Broker/Policies.py
|
|
30
|
+
src/Broker/Priority.py
|
|
25
31
|
src/Broker/Protocol.py
|
|
26
32
|
src/Broker/__init__.py
|
|
27
33
|
src/Broker/Implements/__init__.py
|
|
@@ -76,5 +82,6 @@ test/test_protocol_contracts.py
|
|
|
76
82
|
test/test_runner_hooks.py
|
|
77
83
|
test/test_specifications.py
|
|
78
84
|
test/test_task_messages.py
|
|
85
|
+
test/test_task_priorities.py
|
|
79
86
|
test/test_worker.py
|
|
80
87
|
test/test_worker_startup.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4.12
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -232,6 +232,71 @@ python client.py
|
|
|
232
232
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
233
233
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
234
234
|
|
|
235
|
+
### 작업 우선순위
|
|
236
|
+
|
|
237
|
+
RabbitMQ classic 큐에서는 작업 `parameters`의 RabbitMQ `Subscription`에
|
|
238
|
+
`priority`로 기본 메시지 우선순위, `max_priority`로 큐 최대값을 함께 정의합니다.
|
|
239
|
+
`Run`에 별도의 `priority` 설정을 두지 않습니다.
|
|
240
|
+
`declare()`가 이 설정을 읽어 우선순위 큐를 준비합니다.
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from DefStream.Broker.Implements.RabbitMQ import Subscription
|
|
244
|
+
from DefStream.Worker import (
|
|
245
|
+
Run,
|
|
246
|
+
declare,
|
|
247
|
+
request,
|
|
248
|
+
send,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class Add(
|
|
253
|
+
Run,
|
|
254
|
+
parameters=Subscription(
|
|
255
|
+
queue='defstream.example.priority.add',
|
|
256
|
+
max_priority=5,
|
|
257
|
+
priority=2,
|
|
258
|
+
),
|
|
259
|
+
):
|
|
260
|
+
def run(
|
|
261
|
+
self,
|
|
262
|
+
a: int,
|
|
263
|
+
b: int,
|
|
264
|
+
):
|
|
265
|
+
return a + b
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# broker는 호출자가 연결한 RabbitMQ Connection입니다.
|
|
269
|
+
declare(
|
|
270
|
+
task=Add,
|
|
271
|
+
broker=broker,
|
|
272
|
+
)
|
|
273
|
+
send(
|
|
274
|
+
{'a': 10, 'b': 20},
|
|
275
|
+
task=Add,
|
|
276
|
+
broker=broker,
|
|
277
|
+
)
|
|
278
|
+
# RPC에는 별도로 실행 중인 Worker가 필요합니다.
|
|
279
|
+
result = request(
|
|
280
|
+
{'a': 10, 'b': 20},
|
|
281
|
+
task=Add,
|
|
282
|
+
broker=broker,
|
|
283
|
+
priority=5,
|
|
284
|
+
)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
- 호출의 `priority`가 생략되거나 `None`이면 작업 기본값을 사용합니다.
|
|
288
|
+
명시적 `0`은 가장 낮은 우선순위이며 기본값을 덮어씁니다.
|
|
289
|
+
- 작업 기본값만 지정하면 큐 최대값은 RabbitMQ 상한 `255`입니다.
|
|
290
|
+
최대값만 지정하면 기본값은 `None`이며, 호출값도 없으면 메시지 속성을 생략합니다.
|
|
291
|
+
- 작업 최대값을 초과하는 값, 음수, 정수가 아닌 값과 `bool`은 거부합니다.
|
|
292
|
+
- 작업 설정 없이 호출에서만 지정하면 브로커 범위 `0..255`만 검증합니다.
|
|
293
|
+
우선순위 큐의 사전 선언과 실제 큐 최대값 준수는 호출자 책임입니다.
|
|
294
|
+
- 자식 작업은 설정을 상속하고 유효한 값으로 재정의할 수 있지만 해제할 수는 없습니다.
|
|
295
|
+
- Redis에 우선순위를 요청하면 `NotImplementedError`가 발생합니다.
|
|
296
|
+
우선순위 미지정 시 기존 Redis 동작은 유지합니다.
|
|
297
|
+
- 우선순위는 같은 큐의 대기 메시지 전달에 적용됩니다. 이미 전달·실행 중인
|
|
298
|
+
작업을 선점하거나 여러 작업의 실행·완료 순서를 보장하지 않습니다.
|
|
299
|
+
|
|
235
300
|
### 성공, 실패와 재시도
|
|
236
301
|
|
|
237
302
|
- 작업 실행과 완료 훅이 성공한 뒤 ACK합니다. RabbitMQ RPC는 응답 발행도 ACK보다 먼저 수행합니다.
|
|
@@ -202,6 +202,73 @@ Task bodies must be **mappings with string keys**. Return values must be
|
|
|
202
202
|
serializable by the adapter. A Worker cannot register multiple tasks for the
|
|
203
203
|
same queue: routing selects tasks by queue, not by a type field in the message.
|
|
204
204
|
|
|
205
|
+
### Task priorities
|
|
206
|
+
|
|
207
|
+
For RabbitMQ classic queues, define both the default message `priority` and queue
|
|
208
|
+
`max_priority` in the RabbitMQ `Subscription` supplied as the task's `parameters`.
|
|
209
|
+
There is no separate `priority` setting on `Run`.
|
|
210
|
+
`declare()` reads these settings to provision the priority queue.
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from DefStream.Broker.Implements.RabbitMQ import Subscription
|
|
214
|
+
from DefStream.Worker import (
|
|
215
|
+
Run,
|
|
216
|
+
declare,
|
|
217
|
+
request,
|
|
218
|
+
send,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Add(
|
|
223
|
+
Run,
|
|
224
|
+
parameters=Subscription(
|
|
225
|
+
queue='defstream.example.priority.add',
|
|
226
|
+
max_priority=5,
|
|
227
|
+
priority=2,
|
|
228
|
+
),
|
|
229
|
+
):
|
|
230
|
+
def run(
|
|
231
|
+
self,
|
|
232
|
+
a: int,
|
|
233
|
+
b: int,
|
|
234
|
+
):
|
|
235
|
+
return a + b
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# broker is a RabbitMQ Connection connected by the caller.
|
|
239
|
+
declare(
|
|
240
|
+
task=Add,
|
|
241
|
+
broker=broker,
|
|
242
|
+
)
|
|
243
|
+
send(
|
|
244
|
+
{'a': 10, 'b': 20},
|
|
245
|
+
task=Add,
|
|
246
|
+
broker=broker,
|
|
247
|
+
)
|
|
248
|
+
# RPC requires a separately running Worker.
|
|
249
|
+
result = request(
|
|
250
|
+
{'a': 10, 'b': 20},
|
|
251
|
+
task=Add,
|
|
252
|
+
broker=broker,
|
|
253
|
+
priority=5,
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- Omitting the call's `priority` or passing `None` uses the task default.
|
|
258
|
+
An explicit `0` overrides the default with the lowest priority.
|
|
259
|
+
- Setting only the task default sets the queue maximum to RabbitMQ's limit of
|
|
260
|
+
`255`. Setting only the maximum leaves the default as `None`; without a
|
|
261
|
+
per-call value either, the message priority property is omitted.
|
|
262
|
+
- Values above the task maximum, negative values, non-integers, and `bool` are rejected.
|
|
263
|
+
- Specifying priority only at call time validates only the broker range `0..255`.
|
|
264
|
+
The caller must provision a priority queue and respect its actual maximum.
|
|
265
|
+
- Child tasks inherit settings and may override them with valid values, but cannot
|
|
266
|
+
clear them.
|
|
267
|
+
- Requesting priorities with Redis raises `NotImplementedError`.
|
|
268
|
+
Calls without priorities retain existing Redis behavior.
|
|
269
|
+
- Priority affects delivery of waiting messages within the same queue. It does not
|
|
270
|
+
preempt delivered or running tasks or guarantee execution and completion order.
|
|
271
|
+
|
|
205
272
|
### Success, failures, and retries
|
|
206
273
|
|
|
207
274
|
- ACK follows successful execution and completion hooks. RabbitMQ RPC also publishes the reply before ACK.
|
|
@@ -199,6 +199,71 @@ python client.py
|
|
|
199
199
|
하나의 Worker에서는 같은 큐에 여러 작업을 중복 등록할 수 없습니다.
|
|
200
200
|
메시지 유형을 보고 여러 `Run` 중 하나를 고르는 방식이 아니라 큐별로 작업을 선택합니다.
|
|
201
201
|
|
|
202
|
+
### 작업 우선순위
|
|
203
|
+
|
|
204
|
+
RabbitMQ classic 큐에서는 작업 `parameters`의 RabbitMQ `Subscription`에
|
|
205
|
+
`priority`로 기본 메시지 우선순위, `max_priority`로 큐 최대값을 함께 정의합니다.
|
|
206
|
+
`Run`에 별도의 `priority` 설정을 두지 않습니다.
|
|
207
|
+
`declare()`가 이 설정을 읽어 우선순위 큐를 준비합니다.
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from DefStream.Broker.Implements.RabbitMQ import Subscription
|
|
211
|
+
from DefStream.Worker import (
|
|
212
|
+
Run,
|
|
213
|
+
declare,
|
|
214
|
+
request,
|
|
215
|
+
send,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class Add(
|
|
220
|
+
Run,
|
|
221
|
+
parameters=Subscription(
|
|
222
|
+
queue='defstream.example.priority.add',
|
|
223
|
+
max_priority=5,
|
|
224
|
+
priority=2,
|
|
225
|
+
),
|
|
226
|
+
):
|
|
227
|
+
def run(
|
|
228
|
+
self,
|
|
229
|
+
a: int,
|
|
230
|
+
b: int,
|
|
231
|
+
):
|
|
232
|
+
return a + b
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# broker는 호출자가 연결한 RabbitMQ Connection입니다.
|
|
236
|
+
declare(
|
|
237
|
+
task=Add,
|
|
238
|
+
broker=broker,
|
|
239
|
+
)
|
|
240
|
+
send(
|
|
241
|
+
{'a': 10, 'b': 20},
|
|
242
|
+
task=Add,
|
|
243
|
+
broker=broker,
|
|
244
|
+
)
|
|
245
|
+
# RPC에는 별도로 실행 중인 Worker가 필요합니다.
|
|
246
|
+
result = request(
|
|
247
|
+
{'a': 10, 'b': 20},
|
|
248
|
+
task=Add,
|
|
249
|
+
broker=broker,
|
|
250
|
+
priority=5,
|
|
251
|
+
)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
- 호출의 `priority`가 생략되거나 `None`이면 작업 기본값을 사용합니다.
|
|
255
|
+
명시적 `0`은 가장 낮은 우선순위이며 기본값을 덮어씁니다.
|
|
256
|
+
- 작업 기본값만 지정하면 큐 최대값은 RabbitMQ 상한 `255`입니다.
|
|
257
|
+
최대값만 지정하면 기본값은 `None`이며, 호출값도 없으면 메시지 속성을 생략합니다.
|
|
258
|
+
- 작업 최대값을 초과하는 값, 음수, 정수가 아닌 값과 `bool`은 거부합니다.
|
|
259
|
+
- 작업 설정 없이 호출에서만 지정하면 브로커 범위 `0..255`만 검증합니다.
|
|
260
|
+
우선순위 큐의 사전 선언과 실제 큐 최대값 준수는 호출자 책임입니다.
|
|
261
|
+
- 자식 작업은 설정을 상속하고 유효한 값으로 재정의할 수 있지만 해제할 수는 없습니다.
|
|
262
|
+
- Redis에 우선순위를 요청하면 `NotImplementedError`가 발생합니다.
|
|
263
|
+
우선순위 미지정 시 기존 Redis 동작은 유지합니다.
|
|
264
|
+
- 우선순위는 같은 큐의 대기 메시지 전달에 적용됩니다. 이미 전달·실행 중인
|
|
265
|
+
작업을 선점하거나 여러 작업의 실행·완료 순서를 보장하지 않습니다.
|
|
266
|
+
|
|
202
267
|
### 성공, 실패와 재시도
|
|
203
268
|
|
|
204
269
|
- 작업 실행과 완료 훅이 성공한 뒤 ACK합니다. RabbitMQ RPC는 응답 발행도 ACK보다 먼저 수행합니다.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# 워커 작업 우선순위 구현 기록
|
|
2
|
+
|
|
3
|
+
## 1. 구현 범위
|
|
4
|
+
|
|
5
|
+
[요구사항](./REQUIREMENTS.md)에 따라 작업 정의, 선언, 전송, RPC 요청에 우선순위를 연결했다.
|
|
6
|
+
Redis 구현, 실행 풀 스케줄링, 작업 선점은 변경하지 않았다.
|
|
7
|
+
|
|
8
|
+
## 2. 주요 변경
|
|
9
|
+
|
|
10
|
+
- [Run](../../../src/Worker/Run.py)은 기존 `parameters`의 구독 설정에서
|
|
11
|
+
`priority`와 `max_priority`를 읽는다. 별도의 `Run.priority` 속성이나
|
|
12
|
+
클래스 선언 키워드는 제공하지 않는다. 구독 객체와 매핑을
|
|
13
|
+
모두 지원하며, 기본값과 최대값의 타입·하한 및 상호 범위를 검증한다.
|
|
14
|
+
- 자식 작업은 부모 구독 설정을 상속한다. 구독 설정을 재정의할 때 상속된 기본값이나
|
|
15
|
+
최대값을 제거하면 오류로 거부한다. 변경하려면 유지할 값도 새 구독 설정에 명시한다.
|
|
16
|
+
- [메시지 API](../../../src/Worker/Message.py)의 `send`, `request`에 키워드 전용
|
|
17
|
+
`priority`를 추가했다. 호출값이 `None`이면 작업 기본값을 사용하며 `0`을 보존한다.
|
|
18
|
+
- [PrioritySupport](../../../src/Broker/Connection.py) 계약으로 지원 브로커의
|
|
19
|
+
구독 정규화와 우선순위 발행을 구분한다. 기존 브로커 계약은 유지한다.
|
|
20
|
+
- 우선순위를 전혀 사용하지 않는 경로는 기존 인자 형태로 호출한다.
|
|
21
|
+
미지원 브로커에 우선순위를 요청하면 선언·발행 전에 `NotImplementedError`를 발생시킨다.
|
|
22
|
+
- [공유 검증 함수](../../../src/Broker/Priority.py)를 작업 및 RabbitMQ 경로에서
|
|
23
|
+
재사용한다. 정수가 아닌 값과 `bool`은 `TypeError`, 범위 오류는 `ValueError`로 처리한다.
|
|
24
|
+
|
|
25
|
+
## 3. 브로커 연계
|
|
26
|
+
|
|
27
|
+
- RabbitMQ `Subscription` 생성·파싱 시 기본값만 있으면 최대값을 `255`로
|
|
28
|
+
정규화한다. 원본 매핑은 변경하지 않으며 기존 구독 객체는 그대로 재사용한다.
|
|
29
|
+
- 작업 최대값이 있으면 이를 우선 사용한다. 호출에서만 지정하면 브로커 허용 범위만
|
|
30
|
+
검증하고 큐 선언·변경·조회는 수행하지 않는다.
|
|
31
|
+
- 작업 본문, 스키마, ACK 및 실행 풀의 처리 흐름은 변경하지 않았다.
|
|
32
|
+
|
|
33
|
+
## 4. 검증 결과
|
|
34
|
+
|
|
35
|
+
- 가상 환경의 Python과 기존 `unittest` 러너로 전체 코어 테스트 137개를 실행했다.
|
|
36
|
+
129개 통과, 선택적 통합 테스트 등 8개 건너뜀.
|
|
37
|
+
- 새 우선순위 테스트 7개로 기본값, 최대값, `0`, 호출 재정의, RPC 전달,
|
|
38
|
+
Redis 거부·기존 전송, 상속 및 잘못된 설정을 검증했다.
|
|
39
|
+
- Windows 기본 CP949 출력에서는 기존 시작 배너가 인코딩 오류를 발생시켜,
|
|
40
|
+
`PYTHONIOENCODING=utf-8`, `PYTHONUTF8=1`로 실행하여 통과했다.
|
|
41
|
+
관련 없는 시작 배너 코드는 수정하지 않았다.
|
|
42
|
+
- 변경한 코어 소스의 Pylance 진단에 오류가 없음을 확인했다.
|
|
43
|
+
- Redis 회귀 테스트도 14개 중 10개 통과, 선택적 통합 테스트 4개 건너뜀으로 확인했다.
|
|
44
|
+
- 테스트 도구에서 테스트를 발견하지 못하여 저장소의 `unittest discover`로 검증했다.
|
|
45
|
+
- 후속 Docker RabbitMQ 3.13.7 검증에서 어댑터 전체 35개 테스트가 모두 통과했다.
|
|
46
|
+
코어 메시지·우선순위 테스트도 실제 RabbitMQ 옵션을 활성화하여 18개 중
|
|
47
|
+
16개 통과, Redis 전용 통합 테스트 2개 건너뜀을 확인했다.
|
|
48
|
+
- 기본값을 `Subscription.priority`로 통합한 뒤 전체 코어 테스트를 재실행했다.
|
|
49
|
+
RabbitMQ 실서버 옵션을 활성화하여 137개 중 133개 통과, 4개 건너뜀을 확인했다.
|
|
50
|
+
Redis 회귀 테스트는 14개 중 10개 통과, 4개 건너뜀이다.
|
|
51
|
+
- 코어의 수정된 소스는 Pylance 오류가 없었다. RabbitMQ 원본 경로는 기존 상대
|
|
52
|
+
import 해석 문제 등이 남아 있어 전체 정적 분석 통과로 간주하지 않는다.
|
|
53
|
+
|
|
54
|
+
실행 명령은 작업 폴더 루트 기준이다.
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
$env:PYTHONIOENCODING = 'utf-8'
|
|
58
|
+
$env:PYTHONUTF8 = '1'
|
|
59
|
+
.\.venv\Scripts\python.exe -m unittest discover -s .\DefStream\test
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 5. 공통 브로커 참조 경로 통일
|
|
63
|
+
|
|
64
|
+
- 구현체가 공통 인터페이스와 요소를 `from DefStream.Broker import ...`로 참조하도록 공개 경로를 통일했다.
|
|
65
|
+
- 공통 패키지에서 `Requeue`, `Reject`, `validate_priority`를 추가로 공개했다.
|
|
66
|
+
- RabbitMQ와 Redis 구현체의 상위 상대 import를 제거했다. 구현체 내부 import는 유지했다.
|
|
67
|
+
- RabbitMQ 실서버 테스트 38개 통과, Redis 테스트 10개 통과·4개 건너뜀,
|
|
68
|
+
코어 메시지 테스트 16개 통과·2개 건너뜀을 확인했다.
|
|
69
|
+
|
|
70
|
+
## 6. 관련 문서
|
|
71
|
+
|
|
72
|
+
- [사용 설명서](../../../README.md)
|
|
73
|
+
- [RabbitMQ 구현 기록](../../../../DefStream-RabbitMQ/issues/feature/1/IMPLEMENTS.md)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# 워커 작업 우선순위 지원
|
|
2
|
+
|
|
3
|
+
## 변경 전 (AS-IS)
|
|
4
|
+
|
|
5
|
+
작업을 대상으로 하는 `declare`, `send`, `request`에서는 큐의 우선순위 설정과
|
|
6
|
+
메시지 우선순위를 지정할 수 없었습니다.
|
|
7
|
+
|
|
8
|
+
## 변경 후 (TO-BE)
|
|
9
|
+
|
|
10
|
+
지원 브로커의 작업 구독 설정에 기본·최대 우선순위를 정의하고, `send`와 `request`에서
|
|
11
|
+
메시지별 우선순위를 재정의할 수 있습니다. 현재 지원 브로커는 RabbitMQ입니다.
|
|
12
|
+
|
|
13
|
+
## 사용 방법
|
|
14
|
+
|
|
15
|
+
RabbitMQ 작업의 `parameters`에 `Subscription(priority=2, max_priority=5, ...)`를
|
|
16
|
+
지정하세요. 기본값은 `Run`의 별도 속성이 아니라 구독 설정에 정의합니다.
|
|
17
|
+
호출자가 연결한 `broker`와 구체적인 작업 클래스 `Add`를 사용해 다음처럼 호출합니다.
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from DefStream.Worker import (
|
|
21
|
+
declare,
|
|
22
|
+
request,
|
|
23
|
+
send,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# 작업 구독 설정을 읽어 큐를 준비합니다.
|
|
28
|
+
declare(
|
|
29
|
+
task=Add,
|
|
30
|
+
broker=broker,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# 호출값을 생략하면 작업 구독의 기본 우선순위를 사용합니다.
|
|
34
|
+
send(
|
|
35
|
+
{'a': 1, 'b': 2},
|
|
36
|
+
task=Add,
|
|
37
|
+
broker=broker,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# RPC 요청도 호출별 우선순위를 지정할 수 있습니다.
|
|
41
|
+
result = request(
|
|
42
|
+
{'a': 1, 'b': 2},
|
|
43
|
+
task=Add,
|
|
44
|
+
broker=broker,
|
|
45
|
+
priority=5,
|
|
46
|
+
)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
RPC 결과를 받으려면 해당 작업을 처리하는 Worker가 실행 중이어야 합니다.
|
|
50
|
+
전체 작업 정의와 큐 전환 방법은
|
|
51
|
+
[RabbitMQ 우선순위 사용 안내](https://github.com/yong5eon/DefStream-RabbitMQ/blob/master/issues/feature/1/README.md)를 참고하세요.
|
|
52
|
+
|
|
53
|
+
## 기존 코드에 미치는 영향
|
|
54
|
+
|
|
55
|
+
- 우선순위를 지정하지 않은 기존 호출은 그대로 사용할 수 있습니다.
|
|
56
|
+
- 호출값 생략 또는 `None`은 작업 기본값을 사용하며, `0`은 명시적인 재정의입니다.
|
|
57
|
+
- 기본값만 지정하면 RabbitMQ 큐 최대값은 `255`입니다. 최대값만 지정하고
|
|
58
|
+
호출값도 없으면 메시지 우선순위 속성을 생략합니다.
|
|
59
|
+
- 잘못된 타입이나 범위는 선언·발행 전에 오류로 처리합니다.
|
|
60
|
+
작업 설정 없이 호출에서만 지정하는 경우에는 브로커 허용 범위만 검증하므로,
|
|
61
|
+
실제 우선순위 큐의 사전 선언은 호출자가 보장해야 합니다.
|
|
62
|
+
- 자식 작업에서 구독 설정을 교체한다면 부모의 기본·최대 우선순위도 새 설정에
|
|
63
|
+
명시해야 합니다. 유효한 값으로 재정의할 수 있지만 해제할 수는 없습니다.
|
|
64
|
+
- Redis는 우선순위를 지원하지 않습니다. Redis에 우선순위를 요청하면
|
|
65
|
+
`NotImplementedError`가 발생하며, 미지정 시에는 기존 동작을 유지합니다.
|
|
66
|
+
- 우선순위는 같은 큐의 대기 메시지 전달에만 적용되며, 실행 중 작업의 선점이나
|
|
67
|
+
전역 실행·완료 순서를 보장하지 않습니다.
|
|
68
|
+
|
|
69
|
+
## 브로커 확장 개발자를 위한 공개 요소
|
|
70
|
+
|
|
71
|
+
공통 패키지에서 기존 인터페이스와 함께 `PrioritySupport`, `Requeue`, `Reject`,
|
|
72
|
+
`validate_priority`를 가져올 수 있습니다. 브로커 구현 시 공통 요소는
|
|
73
|
+
`from DefStream.Broker import ...`로 참조하세요.
|
|
74
|
+
기존 우선순위 미지원 브로커에 새 인자 구현을 강제하지 않습니다.
|