From 54654af81531945d90d027cbd295164d3a8295bf Mon Sep 17 00:00:00 2001 From: gahusb Date: Fri, 10 Jul 2026 00:34:47 +0900 Subject: [PATCH] =?UTF-8?q?feat(agent-office):=20node=5Fmonitor=EC=97=90?= =?UTF-8?q?=20naver-fetch(fetcher)=20=EB=93=B1=EC=9E=AC=20+=20http-pull=20?= =?UTF-8?q?=EB=A7=81=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WORKER_REGISTRY에 naver-fetch(kind=fetcher, queue=None) 추가하고 collect_status()에 fetcher kind 분기(from=워커명, to=nas-realestate, type=http-pull)를 추가. /nodes 관측·팀 규칙(모든 워커는 heartbeat+ registry 등재)에 맞춘 naver-fetch 워커 관측 준비. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01EqCYBhvTcdeCTUDX3RhWx9 --- agent-office/app/node_monitor.py | 4 ++++ agent-office/tests/test_node_monitor.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/agent-office/app/node_monitor.py b/agent-office/app/node_monitor.py index 5dec02d..bc53673 100644 --- a/agent-office/app/node_monitor.py +++ b/agent-office/app/node_monitor.py @@ -17,6 +17,7 @@ WORKER_REGISTRY = [ {"name": "task-watcher", "kind": "watcher", "queue": None}, {"name": "ai_trade", "kind": "trader", "queue": None}, {"name": "trade-monitor", "kind": "trader", "queue": None}, + {"name": "naver-fetch", "kind": "fetcher", "queue": None}, ] _redis = None @@ -98,6 +99,9 @@ async def collect_status(redis=None) -> dict: elif w["kind"] == "render": out["links"].append({"from": "nas", "to": w["name"], "type": "redis-queue", "status": _render_link_status(w)}) + elif w["kind"] == "fetcher": + out["links"].append({"from": w["name"], "to": "nas-realestate", "type": "http-pull", + "status": "healthy" if w["alive"] else "down"}) if out["paused"] and not out["paused_reason"]: out["paused_reason"] = "trading" return out diff --git a/agent-office/tests/test_node_monitor.py b/agent-office/tests/test_node_monitor.py index ca6249a..cf7115c 100644 --- a/agent-office/tests/test_node_monitor.py +++ b/agent-office/tests/test_node_monitor.py @@ -206,3 +206,21 @@ async def test_transition_send_failure_retries_next_cycle(monkeypatch): result2 = await nm.check_and_alert(status=dead) assert any("다운" in t for t in result2) assert nm._node_state.get("music-render") is False # 이제 갱신 + + +# ── naver-fetch(fetcher) 등재 ────────────────────────────────────────────── + +def test_naver_fetch_registered(): + from app.node_monitor import WORKER_REGISTRY + entry = next((w for w in WORKER_REGISTRY if w["name"] == "naver-fetch"), None) + assert entry is not None + assert entry["kind"] == "fetcher" and entry["queue"] is None + + +@pytest.mark.asyncio +async def test_naver_fetch_http_pull_link(): + """naver-fetch heartbeat 존재 시 links에 from=naver-fetch·to=nas-realestate·type=http-pull.""" + r = FakeRedis(kv={"worker:naver-fetch:heartbeat": _hb("naver-fetch", "fetcher", "idle")}) + st = await node_monitor.collect_status(redis=r) + link = next(l for l in st["links"] if l["from"] == "naver-fetch") + assert link["type"] == "http-pull" and link["to"] == "nas-realestate" and link["status"] == "healthy"