3.6 KiB
3.6 KiB
쿠폰 충전 회원 락 보강 작업 계획
목적
- 쿠폰 캔 지급 흐름에서도 일반 결제 완료 흐름과 동일하게 회원 row lock을 잡은 뒤 회원 잔액을 증가시킨다.
- 동시 충전/쿠폰 사용 상황에서
Member.charge(...)의+=기반 잔액 증가가 유실되지 않도록 한다.
현재 확인된 문제
ChargeService.chargeByCoupon(...)은CouponType.CAN분기에서 컨트롤러/인증 계층이 전달한member인스턴스에 바로member.charge(0, coupon.can, "pg")를 호출한다.- 일반 결제 완료 경로(
payverseWebhook,payverseVerify,verify,verifyHecto,appleVerify,processGoogleIap)는memberRepository.findByIdForUpdate(...)로 회원 row를 잠근 뒤member.charge(...)를 호출한다. - 쿠폰 충전만 이 패턴과 달라, 같은 회원에게 쿠폰 충전과 다른 잔액 증가 작업이 동시에 실행될 경우 회원 캔 잔액 유실 가능성이 남는다.
확정 범위
ChargeService.chargeByCoupon(...)의CouponType.CAN분기만 최소 수정한다.- 쿠폰 번호 검증, 이미 사용된 쿠폰 검증,
Charge(status = COUPON)생성, 성공 메시지 반환 동작은 유지한다. - 포인트 쿠폰(
CouponType.POINT) 로직은 변경하지 않는다. - 공개 API 요청/응답 스키마는 변경하지 않는다.
- 본 문서를 기준으로 최소 구현을 진행한다.
구현 항목
-
쿠폰 캔 지급 lock 패턴 적용
chargeByCoupon(...)에서member.id!!를 기준으로memberRepository.findByIdForUpdate(...)를 호출한다.- lock 조회로 얻은 회원 엔티티를
couponCharge.member에 연결한다. - lock 조회로 얻은 회원 엔티티에
member.charge(0, coupon.can, "pg")를 호출한다. - lock 조회 실패 시 기존 인증 실패 계열 예외 메시지 패턴을 따른다.
-
회귀 테스트 추가
CouponType.CAN쿠폰 사용 시memberRepository.findByIdForUpdate(...)가 호출되는지 검증한다.- lock 조회로 얻은 회원에 쿠폰 캔이 반영되는지 검증한다.
- 이미 사용된 쿠폰이면 lock 조회와 캔 지급이 진행되지 않는지 검증한다.
CouponType.POINT쿠폰 동작이 변경되지 않았는지 기존 또는 신규 테스트로 확인한다.
-
최소 구현 검증
- 관련 테스트를 먼저 실행해 실패를 확인한다.
- 구현 후 관련 테스트가 통과하는지 확인한다.
./gradlew ktlintCheck를 실행한다.- 필요 시
./gradlew test로 전체 회귀를 확인한다.
검증 항목
- 쿠폰 캔 지급 테스트 통과
- 쿠폰 포인트 지급 기존 동작 유지 확인
./gradlew ktlintCheck./gradlew test
검증 로그
- 문서 작성 검증:
ChargeService.chargeByCoupon(...)의CouponType.CAN분기와 일반 결제 완료 경로의memberRepository.findByIdForUpdate(...)사용 패턴을 확인하고 작업 범위를 문서화했다. - RED 검증:
./gradlew test --tests 'kr.co.vividnext.sodalive.can.charge.ChargeServiceTest'실행 시WantedButNotInvoked로memberRepository.findByIdForUpdate(10L)미호출 실패를 확인했다. - 구현 검증:
CouponType.CAN분기에서 locked member를 조회하고,couponCharge.member와member.charge(...)모두 locked member를 사용하도록 변경했다. - 관련 테스트 검증:
./gradlew test --tests 'kr.co.vividnext.sodalive.can.charge.ChargeServiceTest'통과를 확인했다. - 린트 검증:
./gradlew ktlintCheck통과를 확인했다. - 전체 테스트 검증:
./gradlew test통과를 확인했다.