feat(alarm): trex-core 알람 emitter + trex.alerts exchange (dcy-033 BAT-049, Implemented)
AlarmEmitter(application, best-effort 비차단)+trex.alerts topic exchange 가산·격리+8 CRITICAL code 배선. 608 passed, opus QC PASS, 팀장 e2e(텔레그램 HTTP200) 통과. REQ-098~101 Implemented. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
@@ -12,6 +12,7 @@ import threading
|
||||
from datetime import datetime, time, timedelta, timezone
|
||||
from typing import Callable, Optional
|
||||
|
||||
from trex_core.application.alarm_emitter import AlarmEmitter
|
||||
from trex_core.application.broker_port import BrokerPort
|
||||
from trex_core.application.portfolio import (
|
||||
DegradedReason,
|
||||
@@ -40,6 +41,7 @@ class SnapshotScheduler:
|
||||
slot_repo=None,
|
||||
slot_service=None,
|
||||
instance_key: str = "default",
|
||||
alarm_emitter: Optional[AlarmEmitter] = None,
|
||||
) -> None:
|
||||
self._read = read_port
|
||||
self._store = store
|
||||
@@ -55,6 +57,8 @@ class SnapshotScheduler:
|
||||
self._slot_service = slot_service
|
||||
self._instance_key = instance_key
|
||||
self._last_universe_size: Optional[int] = None
|
||||
# dcy-033 / REQ-100: best-effort alarm emitter.
|
||||
self._alarm_emitter = alarm_emitter
|
||||
|
||||
# ---- callable from a daemon thread loop --------------------------------
|
||||
def run_forever(self, stop: threading.Event, *, tick_sec: float = 60.0) -> None:
|
||||
@@ -88,6 +92,13 @@ class SnapshotScheduler:
|
||||
DegradedReason.PORTFOLIO_HUB_UNAVAILABLE, str(exc)
|
||||
)
|
||||
_log.warning("whoami failed: %s", exc)
|
||||
# dcy-033 / REQ-100: CRITICAL alarm — portfolio hub unavailable.
|
||||
if self._alarm_emitter is not None:
|
||||
self._alarm_emitter.publish_alarm(
|
||||
"portfolio_hub_unavailable",
|
||||
"portfolio-hub whoami 실패: 포트폴리오 정보 부실화",
|
||||
fields={"reason": "whoami_failed"},
|
||||
)
|
||||
return False
|
||||
try:
|
||||
items = self._read.get_portfolios(self._daemon_id)
|
||||
@@ -96,6 +107,13 @@ class SnapshotScheduler:
|
||||
DegradedReason.PORTFOLIO_HUB_UNAVAILABLE, str(exc)
|
||||
)
|
||||
_log.warning("get_portfolios failed: %s", exc)
|
||||
# dcy-033 / REQ-100: CRITICAL alarm — portfolio hub unavailable.
|
||||
if self._alarm_emitter is not None:
|
||||
self._alarm_emitter.publish_alarm(
|
||||
"portfolio_hub_unavailable",
|
||||
"portfolio-hub get_portfolios 실패: 포트폴리오 정보 부실화",
|
||||
fields={"daemon_id": self._daemon_id, "reason": "get_portfolios_failed"},
|
||||
)
|
||||
return False
|
||||
except Exception as exc: # noqa: BLE001 - shape/parsing failure
|
||||
self._store.set_degraded(
|
||||
@@ -120,6 +138,7 @@ class SnapshotScheduler:
|
||||
reconcile_core_holdings(
|
||||
slot_repo=self._slot_repo, slot_service=self._slot_service,
|
||||
broker=self._broker, instance_key=self._instance_key,
|
||||
alarm_emitter=self._alarm_emitter, # dcy-033 / REQ-100
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
_log.exception("core-holding divergence reconcile failed")
|
||||
|
||||
Reference in New Issue
Block a user