[14] 커머스 프로젝트 - 주문, 결제 기능 2차 수정
이전 글 $1 구현 목표 기존 주문, 결제 기능에 대한 전체적인 로직을 변경합니다. 주요 변경 사항은 다음과 같습니다. 주문 생성 시 PENDING 상태 주문 취소 로직 제거 주문 생성 시 재고 차감 로직 재거 재고 차감을 결제 승인 이후로 이전 테스트에서 발견한 주문 생성 문제 해당 글에서는 작성하지 않았지만 K6 동시성 테스트를 진행하면서 아래와 같은 문제를 발견했습니다. 기존 주문 생성 흐름은 다음과 같습니다. <br / 문제가 발생하는 케이스 동시에 10개의 주문 생성 요청이 들어오면 아래와 같은 흐름이 진행됩니다. 문제가 발생하는 케이스는 아래와 같습니다. 1. 주문 생성 요청을 동시에 10개 진행합니다. 2. PENDING 주문이 없는 경우 모든 요청이 다음 단계 실행합니다. 3. 10개의 신규 PENDING 주문이 생성됩니다. 4. 이후 다시 주문 생성을 실행하면, 최근 PENDING 주문 1개만 실행되기 때문에 9개의 주문이 남겨집니다. 해결 방법 - 비즈니스 로직 변경 동시성 문제를 해결하기 위해 주문 생성이 담당하는 책임을 단순화했습니다. 주문 생성 단계에서 하던 작업을 결제 승인 단계로 이전합니다. 기존 PENDING 주문 취소 기능은 제거합니다. 재고 차감 기능은 제거합니다. PENDING 주문 생성은 그대로 유지합니다. 1단계 주문 생성 주문 생성 단계에서는 순수하게 PENDING 상태의 주문만 생성합니다. 기존 PENDING 주문 취소와 재고 차감 로직을 제거했습니다. 단순하게 상품 정보를 조회해 OrderItem을 생성하고, PENDING 주문을 저장합니다. 2단계 Toss PG 결제 진행 주문이 생성되면 프론트에서 Toss SDK 위젯을 사용해 결제를 진행합니다. Toss에 전달하는 주문 ID는 형식으로 가공합니다. orderId: 내부 DB 조회용 주문 ID toosOrderId: Toss API 전달용 (재시도 허용을 위해 Date.now() 사용) 3단계 - 결제 대기 (PENDING 결제 생성) 페이지에서 Payment 레코드를 생성합니다. REQUIRES\NEW 속성을 사용해서 결제 승인 트랜잭션과 독립적으로 동작하도록 구현합니다. Toss PG 승인이 실패하더라도 PENDING 상태의 결제는 보존됩니다. 4단계 - 결제 승인 요청 PENDING 결제가 생성된 뒤, 내부 서버에서 Toss 승인 API를 호출합니다. Toss는 결제 요청 완료 후 10분 이내에 승인을 하지 않으면 자동으로 취소 처리됩니다. 따라서 프론트에서 리다이렉트를 받은 직후 바로 승인 요청을 해야합니다. 5단계 - 내부 결제 승인 처리 (재고 차감) Toss PG 승인이 완료되면 내부에서 아래 작업을 순차로 처리합니다. <br / 재고 차감 순서 - 데드락 방지 여러 상품을 동시에 구매하는 경우, 재고 차감 순서가 달라지면 데드락이 발생할 수 있습니다. productId를 오름차순으로 정렬하고 순서대로 재고를 차감하면, 모든 트랜잭션이 동일한 순서로 Lock을 획득하므로 데드락이 발생하지 않습니다. 6단계 - 재고 부족 처리 결제 승인은 성공했지만 재고가 부족한 경우, 승인 트랜잭션 자체가 롤백됩니다. 재고 부족으로 결제 상태를 APPROVE로 변경하는 트랜잭션이 롤백되면 주문도 CONFIRMED 상태가 되지 않습니다. 프론트에서는 에러 응답을 받으면 별도로 주문 취소 API를 호출해 주문을 명시적으로 CANCELLED 처리합니다. 7단계 - 환불 결제 승인 완료 이후 환불이 필요한 경우의 흐름입니다. <br / 전체 플로우 정리 이번 리팩토링의 핵심은 주문 생성의 책임을 최소화 하는 것입니다. 주문 생성 단계는 순수하게 PENDING 주문을 생성하는 일만 합니다. 재고 차감과 상태 전환은 결제 승인이 확전된 시점에 한 번에 처리합니다. 이렇게 하면 동시 요청에서 발생하는 코드 자료 <https://github.com/dodudi/commerce-spring-nextjs/tree/version/v1 참고 자료 <https://grafana.com/docs/k6/latest/set-up/install-k6/ <https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/