[STK8-04] 백엔드 ClaudeGatewayImpl Codex fallback 추가
작업 내용 (설계 의도)
변경 사항
ClaudeGatewayImpl은 현재 ProcessBuilder(["claude", "-p", ...]) 단일 호출만 한다.
Claude CLI 실패(타임아웃·exit non-zero) 시 codex -q로 동일 프롬프트를 재시도하는 fallback 레이어를 추가한다.
설계 방향: 새 인프라 구현체 CodexGatewayImpl을 만들고,
FallbackClaudeGateway 데코레이터가 Claude → Codex 순서로 위임한다.
ChatConfig에서 FallbackClaudeGateway를 primary bean으로 등록한다.
기존 ClaudeGatewayImpl·ClaudeGateway 인터페이스는 수정하지 않는다.
ClaudeGateway (domain interface)
├── ClaudeGatewayImpl ← 기존 (Claude CLI)
├── CodexGatewayImpl ← 신규 (Codex CLI)
└── FallbackClaudeGateway ← 신규 데코레이터 (1차→2차 위임)
실패 감지 조건
IllegalStateException(타임아웃·exit non-zero) catch- 응답 문자열에
context length/token limit/rate limit/maximum context포함
양쪽 다 실패 시
ChatGatewayUnavailableException을 던져 상위에서 500 응답 처리.
다이어그램
처리 흐름
sequenceDiagram participant DS as ChatDomainService participant FB as FallbackClaudeGateway participant CL as ClaudeGatewayImpl participant CO as CodexGatewayImpl DS->>FB: run(prompt) FB->>CL: run(prompt) alt Claude 성공 CL-->>FB: response FB-->>DS: response else Claude 실패 FB->>CO: run(prompt) alt Codex 성공 CO-->>FB: response FB-->>DS: response else Codex 실패 FB-->>DS: ChatGatewayUnavailableException end end
클래스 의존
flowchart LR DS[ChatDomainService] --> GW[ClaudeGateway] FB[FallbackClaudeGateway] -.->|implements| GW FB --> CL[ClaudeGatewayImpl] FB --> CO[CodexGatewayImpl] CL -.->|implements| GW CO -.->|implements| GW
테스트 케이스
- Claude 성공 → Codex 미호출, Claude 응답 반환
- Claude 타임아웃 → Codex fallback 호출됨
- Claude exit non-zero → Codex fallback 호출됨
- Claude 토큰 한도 감지 → Codex fallback 호출됨
- Codex 성공 → Codex 응답 반환
- Claude·Codex 둘 다 실패 → ChatGatewayUnavailableException 발생