Library · Kotlin · Spring Boot
bk-spring-idempotent
Spring Boot용 Stripe 스타일 @Idempotent 어노테이션. 하나의 어노테이션으로 Spring MVC 엔드포인트에 프로덕션 수준의 Idempotency-Key 처리를 붙입니다. 김빌(Bill Kim)이 직접 설계하고 메인테이닝하는 Kotlin/coroutine-native 오픈소스 라이브러리입니다.
한 줄 요약
@Idempotent 한 줄로 끝나는 API. Idempotency-Key 헤더만 보면, 같은 키 + 같은 본문이면 캐시된 응답을 그대로 돌려주고, 같은 키 + 다른 본문이면 422 Unprocessable Entity, 키 없으면 일반 엔드포인트처럼 동작합니다.
@RestController
class PaymentsController(private val payments: PaymentService) {
@PostMapping("/charges")
@Idempotent // ← that's the whole API
fun charge(@RequestBody req: ChargeRequest): ChargeResponse =
payments.charge(req)
}
왜 만들었나
모든 mutating HTTP API는 Idempotency-Key가 필요합니다. 없으면 네트워크 재시도가 결제를 두 번 일으키고, 중복 발송하고, 도메인 상태와 로그가 어긋납니다. Kotlin/Spring Boot 생태계에는 다음 선택지가 있었습니다:
- 직접 만들기 — 첫 버전은 50줄, "정확한" 버전은 500줄. 동시성 race, body 해시 mismatch, 응답 재생, TTL eviction, 분산 스토리지까지 다 신경써야 합니다.
- Stripe-mason 같은 자바 라이브러리 — 존재하지만 자바 우선이고 WebFlux와 잘 안 맞습니다.
suspend친화적이거나 Spring Boot 3 autoconfigure starter를 같이 주는 건 없습니다. - API 게이트웨이 플러그인 — Kong, Tyk 등. 운영 부담이 크고 인-프로세스 테스트엔 도움 안 되며, 응답 본문 재생도 못합니다.
bk-spring-idempotent는 작은 인-프로세스 중간 옵션입니다. 어노테이션 하나, autoconfigure, sealed Outcome 타입으로 컴파일 단계에서 Fresh / Replayed / Concurrent / BodyMismatch 처리를 강제, Micrometer 메트릭 기본 노출, suspend-네이티브 코어 + MVC 인터셉터 브릿지.
주요 기능
- 어노테이션 하나. XML 없음, 수동 인터셉터 와이어링 없음.
IdempotencyStoreSPI — JDBC(H2/Postgres 자동 감지), in-memory 기본 제공. Redis/Mongo는 SPI 구현해서 붙임.- Sealed
Outcome타입 — 컴파일러가 Fresh / Replayed / Concurrent / BodyMismatch 분기를 강제. - Spring Boot autoconfigure + Micrometer 메트릭.
- Coroutine-네이티브 코어. 전 구간 suspend, MVC 인터셉터는
runBlocking으로 브릿지 — 전통적 blocking 컨트롤러에서도 동작.