STK11-02 cache-first 조회 전환·refresh 파라미터

작업 내용 (설계 의도)

변경 사항

aggregator 조회 경로를 cache-first(Redis → MySQL 스냅샷 → ML)로 전환해, 캐시 hit 시 ML(claude)을 호출하지 않게 한다. (선행: STK11-01 SnapshotGateway)

  • domain SignalDomainService
    • getSignal(symbol, refresh)refresh=false: Redis hit 반환 → miss 시 SnapshotGateway.findSignal hit 반환(+Redis 워밍) → miss 시 ML fresh 호출 후 Redis+Snapshot 적재. refresh=true: 캐시 무시 ML 호출 후 적재
    • getRecommendations(limit, refresh) 동일 패턴
    • ML 실패 시 기존 폴백(스냅샷/Redis) 유지, 전무 시 SignalUnavailableException
  • application GetSignalUseCase/GetRecommendationsUseCaserefresh 인자 전달
  • presentation SignalApiController@RequestParam(defaultValue="false") refreshgetSignal·getRecommendations에 추가 (FE는 이미 ?refresh= 전송 중)

롤백

aggregator 이전 버전 재배포로 즉시 원복 (스키마 변경 없음).

다이어그램

처리 흐름 (refresh=false)

sequenceDiagram
    participant C as SignalApiController
    participant DS as SignalDomainService
    participant CR as Redis
    participant Snap as SnapshotGateway
    participant ML
    C->>DS: getSignal(symbol, false)
    DS->>CR: findSignal
    alt Redis hit
        CR-->>DS: result
    else miss
        DS->>Snap: findSignal
        alt Snapshot hit
            Snap-->>DS: result (fromCache)
            DS->>CR: saveSignal
        else miss
            DS->>ML: GET /signals (claude)
            DS->>CR: saveSignal
            DS->>Snap: saveSignal
        end
    end
    DS-->>C: result

테스트 케이스

  • refresh=false + Redis hit → ML·Snapshot 미호출
  • refresh=false + Redis miss + Snapshot hit → ML 미호출, fromCache=true, Redis 워밍
  • refresh=false + Redis·Snapshot miss → ML 호출 후 Redis·Snapshot 저장
  • refresh=true → 캐시 무시하고 ML 호출 후 저장
  • ML 실패 + Snapshot 존재 → Snapshot 반환
  • ML 실패 + 캐시 전무 → SignalUnavailableException
  • getRecommendations도 위 케이스 동일 적용
  • SignalApiControllerrefresh 쿼리 파라미터를 UseCase로 전달한다
  • fromCache=true 응답에 X-Cache: HIT 헤더가 포함된다