fix: 하네스 제거 및 keycloak 문서 보강
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../../vault/10-projects/errors/idempotency-expired-row-reclaim-409-loop-2026-06-09.md
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: error / idempotency-expired-row-reclaim-409-loop-2026-06-09
|
||||
source_type: error-note
|
||||
status: raw
|
||||
related_branches: [feature-rate-limit-idempotency-contract]
|
||||
related_projects: [ca-skeleton]
|
||||
tags: [error, ca-skeleton, idempotency, concurrency, ttl]
|
||||
created: 2026-06-09
|
||||
status_label: resolved
|
||||
---
|
||||
|
||||
# error: idempotency-expired-row-reclaim-409-loop-2026-06-09
|
||||
|
||||
> Layer: `raw/errors/` — TDD 중 발견한 만료 row 재선점 누락 버그.
|
||||
|
||||
## Parent / 부모
|
||||
|
||||
- [[raw/branch-notes/feature-rate-limit-idempotency-contract]]
|
||||
|
||||
## 증상 / Symptom
|
||||
|
||||
`IdempotencyExecutor`의 `expired_record_is_treated_as_absent_and_reclaimed` 테스트가
|
||||
`IdempotencyInFlightException`(409)으로 실패. 만료된 idempotency record가 있을 때 새 요청이
|
||||
재처리되지 못하고 in-flight 409로 오판됨.
|
||||
|
||||
## 원인 / Root cause
|
||||
|
||||
`IdempotencyStore.find(scope, now)`는 만료 row를 `Optional.empty()`로 반환하지만, 저장소의
|
||||
`tryBegin`(insert)이 **여전히 존재하는** 만료 row와 unique 제약에서 충돌 → `false` 반환.
|
||||
executor는 "타 호출자가 선점했다"고 판단해 200ms wait 후 409. 즉 `find`의 만료 필터와
|
||||
`tryBegin`의 물리 row 존재가 불일치.
|
||||
|
||||
## 해결 / Resolution
|
||||
|
||||
만료 row는 **재선점 가능**해야 한다는 계약을 명문화:
|
||||
- 포트 `IdempotencyStore.tryBegin` javadoc에 "expired record는 reclaim 대상" 명시.
|
||||
- 실제 어댑터(`IdempotencyStoreAdapter.tryBegin`)는 lookup 후 `expiresAt <= now`면 `delete`
|
||||
후 insert (caller 트랜잭션 내 atomic, unique 제약 + `DataIntegrityViolationException`로 race 중재).
|
||||
- 테스트 fake(`FakeStore.find`)는 read 시 만료 row를 lazy purge.
|
||||
|
||||
## 교훈 / Lesson
|
||||
|
||||
만료(soft delete/TTL) 시맨틱은 **읽기 필터와 쓰기 선점이 같은 기준**을 공유해야 한다.
|
||||
read에서만 만료를 숨기고 write 경로가 물리 row를 그대로 보면 "유령 충돌"이 발생한다.
|
||||
관련: [[raw/branch-notes/feature-rate-limit-idempotency-contract]]
|
||||
Reference in New Issue
Block a user