[BE-06] 평가 클라이언트 구현 (FeatureFlagEvaluatorImpl) + 폴백 + 노출 집계
작업 내용 (설계 의도)
변경 사항
공용 평가 진입점(FR-2·FR-12) 구현 + 폴백 체인(FR-11) + 노출 카운트(FR-13). 근거 TDD: ../TDD.md Sequence(평가)·“실패 경로”. 다른 도메인은 이 구현이 제공하는 common.FeatureFlagEvaluator 빈만 주입해 보일러플레이트 없이 평가한다.
FeatureFlagEvaluatorImpl(common.FeatureFlagEvaluator구현, infrastructure): 폴백 체인 = LocalStore.get → (미스) LocalStore.refresh(Redis→MySQL) → 스냅샷 null/ARCHIVED면 호출부 default → 아니면 스냅샷을FeatureFlag.evaluate(context)로 위임 후FeatureEvaluation을 boolean/variant로 매핑.isEnabled: On→true, Off→false, Assigned→true. null/archived→default.variant: Assigned(n)→n, 그 외→default.- 노출 집계(FR-13): 평가 시 Micrometer counter
feature_flag_evaluations_total{key}증가. - Redis·MySQL 모두 실패해도 로컬 마지막 성공 스냅샷이 있으면 그것으로 평가, 없으면 default — 예외를 호출부로 전파하지 않는다. 폴백 경로 진입 시
redis-degraded(warning,source=feature-flag) 발신(senior-pm 정합 #2).
의존
- BE-01 (common.FeatureFlagEvaluator·FeatureContext·FeatureFlag.evaluate)
- BE-03 (LocalFeatureFlagStore·CacheStore)
- BE-02 (Repository — 폴백 최종단)
다이어그램
처리 흐름
sequenceDiagram participant S as 소비 서비스 participant E as FeatureFlagEvaluatorImpl participant L as LocalFeatureFlagStore S->>E: isEnabled(key, context, default) E->>L: get(key) alt 히트 L-->>E: snapshot → flag.evaluate else 미스/전부 장애 E-->>S: default end E-->>S: boolean
테스트 케이스 (Testcontainers + MockK 혼합)
- 로컬 스냅샷에 GlobalToggle ON 플래그가 있으면 isEnabled가 true를 반환한다
- 정의되지 않은 key는 호출부 default를 반환한다
- ARCHIVED 플래그는 default를 반환한다(활성 평가 제외)
- Redis·MySQL 모두 다운이고 로컬에 마지막 성공 스냅샷이 있으면 그 값으로 평가한다(예외 미전파)
- 전부 없음(로컬·Redis·MySQL) + 미조회 상태면 default를 반환한다
- PercentageRollout 50% 플래그를 동일 userId로 반복 평가하면 결과가 일관된다(sticky)
- variant()는 VariantBucketing에서 배정된 이름을, 그 외/미존재에서 default를 반환한다
- 평가 1회당 노출 카운터가 1 증가한다