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
6.8 KiB
6.8 KiB
BAT-049 Implementation
- Status: completed
- Batch: BAT-049
Plan Summary
REQ-098(문서) → REQ-099(topology+transport) → REQ-100(AlarmEmitter+배선) → REQ-101(runtime-flows 정합) 순서로 구현. design.md의 4개 Key Decision을 그대로 따름.
Changed Files
| 파일 | 변경 유형 | 내용 |
|---|---|---|
docs/interface-contract.md |
섹션 추가 + 헤더 갱신 | Interface: trex.alerts (알람 채널, dcy-033) 신규 섹션 (7필드 스키마, routing key, topology, CRITICAL code 목록, Update Trigger). Change Log + Last Updated 갱신. 기존 섹션 불변. |
trex_core/adapters/messaging/topology.py |
추가 | ALERTS_EXCHANGE = "trex.alerts" + alarm_routing_key() 함수 |
trex_core/adapters/messaging/rabbitmq.py |
확장 | declare_topology() trex.alerts 선언 추가. publish_alarm_event() 신규. set_alarm_callback() + _fire_alarm_callback() 신규. 콜백 호출 배선 (publish_unavailable_after_reconnect, dlq_publish_failed). Callable import 추가. |
trex_core/adapters/messaging/in_memory.py |
확장 | _alarm_events 리스트 추가. publish_alarm_event() stub + alarm_events() 조회. |
trex_core/application/messaging.py |
확장 | MessagingTransport Protocol에 publish_alarm_event() 추가. |
trex_core/application/alarm_emitter.py |
신규 | AlarmEmitter 클래스. envelope 구성, KST occurred_at, 예외 삼킴+ERROR 로그, None transport skip. |
trex_core/application/execution.py |
배선 | AlarmEmitter import + alarm_emitter 파라미터 + sell_skipped_no_balance + fill_price_unresolvable 발행 배선. |
trex_core/application/reconciliation.py |
배선 | AlarmEmitter import + alarm_emitter 파라미터 + core_holding_broker_flat 발행 배선. |
trex_core/application/ledger_outbox.py |
배선 | AlarmEmitter import + alarm_emitter 파라미터 + ledger_delivery_failed 3지점(conflict_blocked, permanent_failure, dead_lettered) 배선. |
trex_core/application/killswitch.py |
배선 | AlarmEmitter import + alarm_emitter 파라미터 + kill_switch_fired 배선. |
trex_core/application/snapshot_scheduler.py |
배선 | AlarmEmitter import + alarm_emitter 파라미터 + portfolio_hub_unavailable 2지점(whoami_failed, get_portfolios_failed) 배선. reconcile_core_holdings 호출에 alarm_emitter 전달. |
trex_core/runtime/reset.py |
배선 | _emit_reset_alarm() 헬퍼 추가. run_reset() alarm_emitter 파라미터 추가. migration 예외 + schema_ok=False 지점 배선. |
trex_core/runtime/daemon.py |
조립 | AlarmEmitter import. alarm_emitter 생성 (event_publisher 이후). set_alarm_callback() 주입. LedgerWriter, KillSwitchService, SnapshotScheduler, ExecutionService 생성 시 alarm_emitter 주입. 서비스 생성 순서 재배치(alarm_emitter 생성 후 주입 보장). |
tests/application/test_alarm_emitter.py |
신규 | AlarmEmitter 단위 테스트 29개 (8 code × envelope 검증, 8 code × TransportUnavailableError 삼킴, 8 code × 임의 예외 삼킴, None transport skip, fields default, routing key, pika 미import, TELEGRAM 미참조). |
tests/adapters/messaging/test_topology.py |
확장 | test_alerts_exchange_constant, test_alarm_routing_key_format 추가. |
tests/adapters/messaging/test_in_memory_transport.py |
확장 | test_publish_alarm_event_records_event, test_publish_alarm_event_raises_when_unavailable 추가. |
docs/runtime-flows.md |
섹션 추가 + 헤더 갱신 | Flow: 알람 발신 (trex.alerts, dcy-033) 신규 섹션 (발행 흐름, best-effort 정책, 8종 code 목록, trex.events 차이표). 기존 섹션 불변. |
Design Decisions Implemented
KD-1 (rabbitmq.py 어댑터 alarm 콜백 패턴):
RabbitMQTransport.__init__에alarm_callback: Optional[Callable]파라미터 추가.set_alarm_callback()setter 추가 (늦은 주입 — daemon.py에서 AlarmEmitter 생성 후 바인딩)._fire_alarm_callback()내부 헬퍼: callback None guard + 예외 삼킴.publish_event()retry 실패 시publish_unavailable_after_reconnect콜백 호출._publish_dlq()DLQ 실패 시dlq_publish_failed콜백 호출.
KD-2 (reset.py transport None 안전):
_emit_reset_alarm(alarm_emitter, code, title, fields)헬퍼: None guard + 예외 삼킴.run_reset()시그니처에alarm_emitter: Optional[object] = None추가.- migration 예외(raise 전)와 schema_ok=False 지점에서 헬퍼 호출.
KD-3 (publish_alarm_event 별도 메서드):
trex.alertsexchange,mandatory=False,delivery_mode=1(non-persistent).MessagingTransportProtocol +RabbitMQTransport+InMemoryTransport모두 구현.
KD-4 (AlarmEmitter 인터페이스):
AlarmEmitter(transport: Optional[MessagingTransport]).publish_alarm(code, title, *, fields=None, severity="critical").source="trex-core",schema_version="1"고정.occurred_at= KST ISO-8601.
Execution Log
- docs/interface-contract.md — trex.alerts 섹션 추가 (REQ-098 완료)
- topology.py — ALERTS_EXCHANGE + alarm_routing_key() (REQ-099 일부)
- messaging.py — publish_alarm_event Protocol 추가 (REQ-099 일부)
- rabbitmq.py — declare_topology + publish_alarm_event + 콜백 패턴 (REQ-099 완료 + REQ-100 KD-1)
- in_memory.py — publish_alarm_event stub (REQ-099 완료)
- alarm_emitter.py — AlarmEmitter 신규 (REQ-100 핵심)
- execution.py — fill_price_unresolvable + sell_skipped_no_balance (REQ-100 배선)
- reconciliation.py — core_holding_broker_flat (REQ-100 배선)
- ledger_outbox.py — ledger_delivery_failed (REQ-100 배선)
- killswitch.py — kill_switch_fired (REQ-100 배선)
- snapshot_scheduler.py — portfolio_hub_unavailable (REQ-100 배선)
- reset.py — schema_verification_failed + migration_failed (REQ-100 배선)
- daemon.py — AlarmEmitter 생성·주입 + 서비스 생성 순서 재배치 (REQ-100 조립)
- runtime-flows.md — 알람 발신 흐름 섹션 추가 (REQ-101 완료)
- 테스트 작성 (test_alarm_emitter.py 29개, topology/in_memory 추가)
Validation
pytest tests/application/test_alarm_emitter.py -v
→ 29 passed, 0 failed, 0 skipped
pytest --tb=short -q (전체)
→ 608 passed, 47 skipped, 0 failed
ruff check trex_core/ tests/
→ All checks passed!
Remaining Risks
- R-1(Low):
trex.alertsexchange 선언은 실 RabbitMQ에서만 검증 가능 (단위에서 mock). 팀장이 실인프라 통합 테스트 수행 예정. - R-2(Low): daemon.py에서 event_publisher가
InMemoryTransport인 경우set_alarm_callback()이 없어hasattrguard 처리됨 (InMemoryTransport는 콜백 불필요). - R-3(Low): reset.py의
alarm_emitter파라미터가main()(CLI 진입점)에서 None으로 실행됨 — 의도된 동작이나 실인프라 CLI 시나리오에서 알람 미발행.