You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
현재 BudgetStateStore는 getAccumulatedCost()와 addCost()가 분리되어 있고, DefaultBudgetEvaluator는 조회한 값에 예상 비용을 더해 판단만 한다. ConcurrentHashMap.merge()는 덧셈 한 번만 원자적일 뿐 조회 → 검사 → 예약 전체를 보호하지 않는다.
따라서 여러 요청이 같은 잔여 예산을 동시에 보고 모두 허용되는 oversubscription이 발생할 수 있다. reservation ID, active reserved amount, idempotency key 모델도 아직 없다. 또한 현재 budget limit과 누적값은 통화 없는 BigDecimal이어서 서로 다른 통화를 같은 금액처럼 비교할 수 있다.
문제와 현재 코드 근거
현재
BudgetStateStore는getAccumulatedCost()와addCost()가 분리되어 있고,DefaultBudgetEvaluator는 조회한 값에 예상 비용을 더해 판단만 한다.ConcurrentHashMap.merge()는 덧셈 한 번만 원자적일 뿐 조회 → 검사 → 예약 전체를 보호하지 않는다.따라서 여러 요청이 같은 잔여 예산을 동시에 보고 모두 허용되는 oversubscription이 발생할 수 있다. reservation ID, active reserved amount, idempotency key 모델도 아직 없다. 또한 현재 budget limit과 누적값은 통화 없는
BigDecimal이어서 서로 다른 통화를 같은 금액처럼 비교할 수 있다.목표 계약
아래 이름은 예시이며 의미를 우선 고정한다.
BudgetKey는 #27의 target identity와 budget window를 포함한다.safeUpperBoundCost다.committedCost + activeReservedCost + pendingReconciliationLiability + safeUpperBoundCost다.>= BLOCK의미는 [Core] BudgetDecision.BLOCK이 provider 호출을 차단하도록 수정 #25 계약을 재사용한다.통화 불변식
Cost값으로 표현한다.CURRENCY_MISMATCH를 반환한다.구현 가이드
ReservationId,IdempotencyKey,ReservationState.RESERVED, immutable reservation snapshot과 결과 타입을 정의한다.compute, lock 또는 동등한 임계 구역으로 예산 검사·통화 검사·idempotency 검사·예약 생성을 함께 수행한다.BudgetKey를 포함하게 하거나 동등한 방식으로 reservation lookup과 bucket 갱신 사이의 부분 상태를 피한다.Clock은 주입 가능하게 해 테스트를 결정적으로 만든다.internal에 있으면LedgerBudgetComponents같은 public factory를 통해 생성한다.BudgetEvaluator와BudgetStateStore의 유지·대체·migration 방식을 문서화한다.테스트
수백 요청과 terminal 전이 경쟁 검증은 #38에서 담당한다.
Acceptance criteria
safeUpperBoundCost가 예약된다.제외 범위
의존관계와 순서
Source