WIL : 트랜잭션 관리와 외부 결제 API 처리

Skadi·2024년 10월 6일
0

1. 기존 결제 트랜잭션 유지 및 외부 결제 트랜잭션 분리

결제 프로세스에서 외부 결제 API 호출을 별도의 메소드로 분리하고, 그 과정에서 트랜잭션 분리에 대해 고민했습니다. 기본적으로 결제 정보를 생성하는 트랜잭션과 외부 결제를 수행하는 트랜잭션을 분리하여, 외부 결제 API 실패 시에도 결제 정보는 남기되, 결제 상태만 실패로 변경하는 방식으로 개선하였습니다.

2. 트랜잭션 분리 구조

2-1. 결제 생성 메소드 (createPayment)

  • @Transactional을 사용하여 기본 결제 생성 트랜잭션을 유지.
  • 결제 정보를 DB에 저장한 후, 외부 결제 API를 호출.
  • 외부 결제 API에서 오류가 발생할 경우, 생성된 결제 정보는 롤백되지 않고 결제 상태만 실패로 변경.
@Transactional
public PaymentResponseDTO createPayment(PaymentRequestDTO request) {
    // 1. ticketId와 userId를 통해 티켓 유효성 검사(추후 외부 API를 통해 검증)

    // 2. 결제 생성
    Payment payment = createNewPayment(request);
    paymentRepository.save(payment);  // 결제 정보 저장 (트랜잭션 내에서 수행)

    // 3. 외부 결제 API를 호출하여 결제 진행
    try {
        processExternalPayment(payment);  // 외부 결제는 별도의 트랜잭션으로 처리
        payment.updateStatus(PaymentStatus.COMPLETED);  // 성공 시 상태 업데이트
    } catch (ExternalPaymentException e) {
        payment.updateStatus(PaymentStatus.FAILED);  // 실패 시 상태를 실패로 변경
        paymentRepository.save(payment);  // 상태 저장
        throw new PaymentFailedException("카카오페이 결제 실패: " + e.getMessage());
    }

    return toResponseDTO(payment);
}

2-2. 외부 결제 API 처리 메소드 (processExternalPayment)

  • @Transactional(propagation = Propagation.REQUIRES_NEW)을 사용하여 외부 결제 API 호출을 별도의 트랜잭션으로 분리.
  • 외부 결제 API 호출이 실패해도 결제 생성 트랜잭션은 영향을 받지 않으며, 결제 상태만 관리하게 됩니다.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processExternalPayment(Payment payment) {
    try {
        // 1. 외부 결제 API 호출 (카카오페이)
        ReadyResponse readyResponse = kakaoPayService.payReady(payment.getItemName(), payment.getAmount());
        
        // 2. 결제 준비가 성공적으로 이루어졌을 경우 결제 정보 업데이트
        payment.setTid(readyResponse.getTid());
        payment.updateStatus(PaymentStatus.PENDING);  // 결제 준비 상태로 변경
    } catch (ExternalPaymentException e) {
        // 3. 외부 결제 API 실패 시 상태 업데이트
        payment.updateStatus(PaymentStatus.FAILED);
        throw e;  // 예외를 다시 던져 상위에서 처리
    }
}

3. 이 방식의 장점

  1. 트랜잭션 분리로 인한 안정성 확보: 외부 결제 API와 DB 트랜잭션을 분리함으로써, 외부 API 호출 실패 시에도 결제 정보는 롤백되지 않습니다. 따라서 결제 시도에 대한 기록을 남길 수 있습니다.

  2. 트랜잭션 관리의 명확성: 결제 생성과 외부 결제를 별도의 트랜잭션으로 처리하여, 각 단계에서의 오류 처리 및 상태 관리를 명확하게 할 수 있습니다.

  3. 결제 상태 관리 용이: 결제 실패 시에는 트랜잭션이 롤백되지 않고, 결제 상태만 실패로 변경하여 이후 처리에 대한 정보를 남길 수 있습니다.

4. 결론

  • 외부 결제를 별도의 트랜잭션으로 분리하여 처리하는 방식은 MSA에서의 결제 프로세스에서 데이터 일관성을 보장하면서도 외부 결제 API 실패 시의 처리를 더욱 유연하게 만들 수 있었습니다.
  • 기본 트랜잭션 내에서 결제를 생성하고, 외부 결제 실패 시에도 해당 결제 정보는 유지되며, 결제 상태만 적절히 변경하는 방식으로 시스템의 안정성을 강화했습니다.

0개의 댓글