# BAT-013 Design - Status: confirmed - Batch: BAT-013 ## Architecture Summary 다중 인스턴스가 동일 RabbitMQ 에서 split-brain 없이 운영되도록 토폴로지·설정을 인스턴스화한다. 1. **동적 큐명**(`topology.py`): `intent_queue/snapshot_queue/control_queue(instance_key)`. `instance_key in (None,"default")` → 기존 리터럴(`trex.intent.req` 등), 그 외 → `{base}.{instance_key}`. 기존 상수는 default 값으로 보존(하위호환). 2. **exchange**(`topology.py`+`rabbitmq.py`): `trex.direct`(topic,durable) + `trex.broadcast`(fanout,durable). `declare_topology(instance_key)` 가 인스턴스 큐를 direct 에 `{instance_key}.{intent|control|snapshot}` 로 바인딩 + control 큐를 broadcast 에 dual 바인딩. 3. **설정**(`config.py`): `DaemonInstanceConfig(instance_key, portfolio_hub_token)` + `from_toml(path)`(tomllib) + `DaemonConfig.from_config(toml_path)` 가 `from_env()` 결과에 TOML 을 병합(`portfolio_hub_token` → PortfolioHubConfig.token). 4. **진입점**(`daemon.main`): argparse `--config` 필수. instance_key 를 declare/consume 에 일관 전달. ## Changed Areas - Docs: interface-contract.md(routing key)·runtime-flows.md(TOML 기동/라우팅)·project-structure.md(동적 큐명/설정/exchange) — REQ-051. - Modules: - `trex_core/adapters/messaging/topology.py` — 큐명 빌더 + DIRECT/BROADCAST exchange 상수 + `direct_routing_key` - `trex_core/adapters/messaging/rabbitmq.py` — `declare_topology(instance_key="default")` + exchange 선언 + binding(direct per-instance + control dual) + (필요시) broadcast publish helper - `trex_core/runtime/config.py` — `DaemonInstanceConfig` + `from_toml` + `from_config` - `trex_core/runtime/daemon.py` — `--config` argparse(main) + instance_key 보관 + consumer 큐명에 instance_key 적용 + declare_topology(instance_key) - `.gitignore` — 인스턴스 TOML 패턴 - Interfaces: - `intent_queue(instance_key) -> str` 등 (default 하위호환) - `declare_topology(instance_key="default")` - `direct_routing_key(instance_key, channel_type) -> "{instance_key}.{channel_type}"` - `DaemonInstanceConfig.from_toml(path)`, `DaemonConfig.from_config(toml_path)` ## Key Decisions 1. **default = 리터럴 큐명(특수 처리)**: FR-2(suffix)와 FR-5(default 무회귀)의 긴장을 해소 — named instance 만 suffix, default 는 기존 이름 유지. 기존 messaging 테스트/배포 무변경. (planning R-1) 2. **declare_topology 기본 인자 `instance_key="default"`**: 기존 호출부(`transport.declare_topology()`)가 인자 없이도 default 동작 → 호출부 광범위 수정 회피. 3. **exchange 는 항상 선언(default 포함)**: direct/broadcast 는 default 인스턴스에서도 선언·바인딩하되, 기존 직접 큐 reply-to RPC 경로는 그대로 동작(추가 바인딩은 비파괴적). 기존 RPC 회귀 없음(FR-5/AC-6). 4. **TOML 우선 병합**: `from_config` 는 `from_env()` 로 베이스 구성 후 TOML 의 `portfolio_hub_token` 을 PortfolioHubConfig.token 으로 override. `instance_key` 는 TOML 전용. 5. **`--config` 필수**: argparse required. 누락 시 argparse 가 usage 출력 + exit≠0(OQ-2). 단, `from_env()` 단독 호출(테스트/라이브러리)은 계속 가능. 6. **pika per-thread**: 바인딩 추가만, consumer 스레드/커넥션 수 불변(NFR-2). ## Edge Cases - default 큐명 충돌 없음: `*.default` 를 쓰지 않고 리터럴 사용. - TOML 누락 필드/파일 부재 → 명확한 예외(FR-1/AC-4). - broadcast 중복 control 전달 → 핸들러 idempotency(REQ-036/advisory lock, R-3). - 기존 old 큐 잔류 → 자연 소멸(OQ-1), 코드 무관. - snapshot/intent reply-to RPC: 클라이언트가 direct routing key 로 보내든 직접 큐로 보내든, 인스턴스 큐가 direct 바인딩 + 직접 publish 둘 다 수신 가능(하위호환). ## Architecture Impact - runtime-flows: TOML 기동 + directed/broadcast 라우팅 + split-brain 방지 — REQ-051. - project-structure: topology 동적화 + 설정 계층 + exchange — REQ-051. - interface-contract: routing key 계약 — REQ-051. ## Reference Doc Update Plan - interface-contract.md: routing key(`{instance_key}.{channel_type}`)+broadcast+큐명 규칙 (REQ-051 AC-1) - runtime-flows.md: `--config` 기동 + directed/broadcast + split-brain (REQ-051 AC-2) - project-structure.md: 동적 큐명/DaemonInstanceConfig/`--config`/exchange (REQ-051 AC-3)