# ๐Ÿ“Š Issue #5 Phase 1 โ€” ์žฅ์ˆ˜ MQTT ์—ฐ๊ฒฐ ๋ฒค์น˜๋งˆํฌ ์‹ค์ธก - **๋ฌธ์„œ ๋ฒ„์ „**: Rev.1 - **์ธก์ • ์ผ์‹œ**: 2026-09-06 - **๊ธฐ์ค€ ์ปค๋ฐ‹**: Phase 1 ์ปค๋ฐ‹ 4 (`feat(issue-5): persistent MQTT publisher prototype and benchmark harness`) - **ํ•˜๋‹ˆ์Šค**: `python -m lib_py.delegation.bench --n --transport {fake|broker}` - **๊ทผ๊ฑฐ ๋Œ€์ƒ**: `implementation_plan.md` ยง5 "MQTT ์—ฐ๊ฒฐ ์žฌ์‚ฌ์šฉ p50 ๋‹จ์ถ•" ํ•ญ๋ชฉ --- ## 1. ์ธก์ • ํ™˜๊ฒฝ | ํ•ญ๋ชฉ | ๊ฐ’ | |---|---| | Python | 3.9.6 (`.venv`) | | paho-mqtt | 2.1.0 | | ํ”Œ๋žซํผ | darwin-arm64 | | ๋กœ์ปฌ ๋ธŒ๋กœ์ปค | **์—†์Œ** (`mosquitto`, `nats-server`, `docker` ๋ชจ๋‘ ๋ฏธ์„ค์น˜) | | ์‹ค๋ธŒ๋กœ์ปค | `broker.hivemq.com:1883` (PoC ๊ธฐ๋ณธ ๊ณต์šฉ ๋ธŒ๋กœ์ปค, TLS ์—†์Œ) | > โš ๏ธ ๋กœ์ปฌ ๋ธŒ๋กœ์ปค๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์‹ค๋ธŒ๋กœ์ปค ์ˆ˜์น˜๋Š” ๊ณต์šฉ ์ธํ„ฐ๋„ท ๋ธŒ๋กœ์ปค์— ๋Œ€ํ•œ **1ํšŒ ์ธก์ •์น˜**์ด๋ฉฐ, ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ์ขŒ์šฐ๋œ๋‹ค. **๊ฒŒ์ดํŠธ ์กฐ๊ฑด์ด ์•„๋‹ˆ๋‹ค.** ๊ฒŒ์ดํŠธ๊ฐ€ ๊ฑธ๋ฆฐ ๊ฒƒ์€ ์•„๋ž˜ ยง2์˜ ๊ฒฐ์ •์  ์ง€ํ‘œ๋ฟ์ด๋‹ค. --- ## 2. ๊ฒฐ์ •์  ์ง€ํ‘œ โ€” ๊ฐ€์งœ ์ „์†ก (CI ๋‹จ์ • ๋Œ€์ƒ) ํ•ฉ์„ฑ ์—ฐ๊ฒฐ ์ง€์—ฐ 50 ms, N = 50. | ์ง€ํ‘œ | OneShot | Persistent | |---|---:|---:| | ๋ฐœํ–‰ ์ˆ˜ | 50 | 50 | | **์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ ํšŸ์ˆ˜** | **50** | **1** | | ์‹คํŒจ | 0 | 0 | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ p50 | 54.813 ms | **0.002 ms** | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ p95 | 55.049 ms | 0.003 ms | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ max | 55.075 ms | 51.110 ms (์ตœ์ดˆ ์—ฐ๊ฒฐ) | `tests/test_issue5_phase1_delegation.py::test_bench_fake_transport_schema_and_counts`๊ฐ€ "OneShot = N, Persistent = 1" ๋ฐ p50 ๊ฐ์†Œ๋ฅผ ๋‹จ์ •ํ•œ๋‹ค. ๋„คํŠธ์›Œํฌ ์ ‘์ด‰ 0. --- ## 3. ์ •๋ณด์„ฑ ์ง€ํ‘œ โ€” ์‹ค๋ธŒ๋กœ์ปค (๊ฒŒ์ดํŠธ ์•„๋‹˜) `broker.hivemq.com:1883`, N = 5. | ์ง€ํ‘œ | OneShot | Persistent | |---|---:|---:| | ์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ ํšŸ์ˆ˜ | 5 | 1 | | ์‹คํŒจ | 0 | 0 | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ p50 | 1892.728 ms | **275.992 ms** | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ p95 | 1942.762 ms | 875.412 ms | | ๋ฐœํ–‰๋‹น ์ง€์—ฐ max | 1942.762 ms | 875.412 ms (์ตœ์ดˆ ์—ฐ๊ฒฐ) | p50 ๊ธฐ์ค€ ์•ฝ **85% ๋‹จ์ถ•**. ์—ฐ๊ฒฐ ์ˆ˜๋ฆฝ์ด ๋ฐœํ–‰ ์ง€์—ฐ์˜ ์ง€๋ฐฐ์  ์š”์†Œ์ž„์„ ๋ณด์—ฌ์ค€๋‹ค. ### 3-1. ์ด ํ”„๋กœํ† ํƒ€์ž…์˜ ์‹ค์ธก ๋™๊ธฐ Rev.1 ๊ณ„ํš job์˜ `started` ์ด๋ฒคํŠธ๋Š” payload timestamp 05:58:49Z์—์„œ ๋ชจ๋‹ˆํ„ฐ ์ˆ˜์‹  05:59:01.487Z๊นŒ์ง€ **์•ฝ 12.5์ดˆ**๊ฐ€ ๊ฑธ๋ ธ๊ณ , ์›์ธ์€ `CONNECT_ACK_TIMEOUT=10` 1ํšŒ ์‹คํŒจ ํ›„ ์žฌ์—ฐ๊ฒฐ์ด์—ˆ๋‹ค. ๋ณธ job(`ddcaf930`)์˜ `started` ๋ฐœํ–‰์—์„œ๋„ ๊ฐ™์€ CONNACK ๊ฒฝ๊ณ ๊ฐ€ ์žฌํ˜„๋๋‹ค. 1ํšŒ์„ฑ ์—ฐ๊ฒฐ์€ ์ด ๋น„์šฉ์„ ๋งค ์ด๋ฒคํŠธ๋งˆ๋‹ค ๋‹ค์‹œ ์ง€๋ถˆํ•œ๋‹ค. --- ## 4. ํ”„๋กœ์„ธ์Šค ํฌํฌ ์ˆ˜ (์…ธ ๊ฒฝ๋กœ, ๋ถ„์„๊ฐ’) `delegate_publish_event` 1ํšŒ๋‹น: | ๊ตฌํ˜„ | fork | |---|---:| | ๋ ˆ๊ฑฐ์‹œ (`_delegate_publish_event_legacy`) | 3 (`$(_delegate_py_bin)`, `$(_delegate_script)`, python) | | ์‹ ๊ทœ (`-m lib_py.delegation.cli`) | 3 (`$(_delegate_py_bin)`, `$(_delegate_script)`, python) | > ๊ณ„ํš์„œ D8์€ ์‹ ๊ทœ ๊ฒฝ๋กœ๊ฐ€ 2 fork์ผ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ์œผ๋‚˜, **์‹ค์ œ ๊ตฌํ˜„์€ 3 fork๋กœ ๋™์ผํ•˜๋‹ค.** `_delegate_script publish_event.py` ํ˜ธ์ถœ์„ ์œ ์ง€ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋ฉฐ, ์ด๋Š” ์˜๋„์ ์ด๋‹ค: ๊ทธ ํ˜ธ์ถœ์ด "์Šคํฌ๋ฆฝํŠธ ํŠธ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค"๋Š” ๋น„์น˜๋ช… ๊ณ„์•ฝ(C-02)์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์œ ์ผํ•œ ์ง€์ ์ด๋‹ค. ์ด๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด fork 1ํšŒ๋ฅผ ์•„๋ผ๋Š” ๋Œ€์‹  ๊ณ„์•ฝ์ด ๋ฐ”๋€๋‹ค. fork ์ ˆ๊ฐ์€ Phase 4์—์„œ ๊ณ„์•ฝ๊ณผ ํ•จ๊ป˜ ์žฌ๊ฒ€ํ† ํ•œ๋‹ค. --- ## 5. ํ”„๋กœ๋•์…˜ ์ ์šฉ ๋ฒ”์œ„ **Phase 1์—์„œ ์žฅ์ˆ˜ ์—ฐ๊ฒฐ์€ ํ”„๋กœ๋•์…˜ ๊ฒฝ๋กœ์— ์“ฐ์ด์ง€ ์•Š๋Š”๋‹ค.** CLI์™€ ์…ธ ํ—ฌํผ๋Š” ๋ฐœํ–‰ 1ํšŒ ํ›„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋˜๋ฏ€๋กœ ์žฌ์‚ฌ์šฉ ์ด๋“์ด ์—†๊ณ , ๋‘ ๊ฒฝ๋กœ ๋ชจ๋‘ `OneShotPublisher`๋ฅผ ๊ณ„์† ์“ด๋‹ค. ์ฒซ ์†Œ๋น„์ž๋Š” Phase 2a์˜ ์žฅ์ˆ˜ ์—”์ง„์ด๋‹ค. ## 6. ์žฌํ˜„ ๋ช…๋ น ```bash export PYTHONPATH="$PWD/.agents/skills" .venv/bin/python -m lib_py.delegation.bench --n 50 --transport fake --connect-latency-ms 50 # ์‹ค๋ธŒ๋กœ์ปค(์ž„์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํ•„์š”) .venv/bin/python -m lib_py.delegation.cli submit --prompt bench --registry-dir .mam/jobs .venv/bin/python -m lib_py.delegation.bench --n 5 --transport broker --job --registry-dir .mam/jobs ```