현재 결제 로직은 다음과 같다.
어떤 서비스가 가장 오래 걸리는가
즉, 현재 결제 이후 결제 문제가 생겨 이를 취소하는 과정이 가장 큰 시간을,
혹은 결제와 구매정보 변동까지 되어 이를 저장하는 과정이 두번째로 큰 시간을 사용함을 알 수 있었다.
*의외로, MSA구조에 따른 MINISERVICE간의 통신엔 큰 시간이 소요되지 않았다.
로직의 속도 증가가 더 큰
로직을 더 좋게 만들어보자
1. 결제가 잘못되어 취소를 보내야 할때
public Mono<Boolean> validateandSave (
PortOnePaymentRecords portOnePaymentRecords,
String paymentId,
int frontPaymentClaim,
String useremail)
{
//프론트에서 전달한 결제 정보가 일치한지, portone에서 실제로 했던 결제 금액이 일치한지 확인
if (portOnePaymentRecords.getAmount().getTotal() == frontPaymentClaim) {
log.info("결제 정보가 일치합니다. 결제 정보를 저장합니다.");
//portone에서 제공하는 날짜 type에 따른 교환
Timestamp purchaseAt = changeDateFormat(portOnePaymentRecords.getRequestedAt()) ;
Payment payment = Payment.builder()
.paymentid(paymentId)
.status(portOnePaymentRecords.getStatus())
.purchaseat(purchaseAt) // 변환 필요
.ordername(portOnePaymentRecords.getOrderName())
.totalamount(frontPaymentClaim)
.build();
paymentRepository.save(payment) ; //저장.
return Mono.just(Boolean.FALSE); //문제없음
} else {
log.info("결제 정보가 일치하지 않습니다. 취소 요청을 보냅니다.") ;
CancelRequest cancelRequest = new CancelRequest("결제 금액과 DB 확인 결과 맞지 않습니다");
Mono<CancelResponse> cancelResponseMono = portOneWebClient
.post()
.uri("/payments/{paymentId}/cancel", paymentId)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(cancelRequest))
.retrieve()
.bodyToMono(CancelResponse.class);
// 악의적 공격으로 가정, 결제 취소 후 해당 정보 저장.
Timestamp purchaseAt = changeDateFormat(portOnePaymentRecords.getRequestedAt()) ;
Payment payment = Payment.builder()
.paymentid(paymentId)
.status("DENIED")
.purchaseat(purchaseAt)
.ordername(portOnePaymentRecords.getOrderName())
.totalamount(frontPaymentClaim)
.build();
paymentRepository.save(payment);
//결제 취소 완료. 이후 exception 유발 필요-
throw new PaymentClaimAmountMismatchException();
}
}
해당 부가 결제 검증, 또 결제 취소를 진행하는 부.
PORTONE에서 TOKEN을 받아올때의 시간에 비해 취소시 너무 많은 시간이 소요된다는 점을 변경해야 하겠다.
1. 취소 에 대한 내용을 메소드화하여 사용하자.
현재 MEMBERSERVICE가 켜지지않았을때, MEMBER SERVICE 동작 과정에서 문제가 생겼을때 모두 각각 취소 요청을 구현하여 동작한다. 해당 METHOD는 내부적으로 겹치는 부분이므로, 이를 METHOD화 하여 활용하자.
예외도 처리하자.
처리한 수 많은 예외들. 통신상에서 발생하는 NOSUCHELEMENT, DB에서의 문제 뿐만 아니라
MSA 구조 상 발생하는 통신에 관련된 문제를 분리하였다.
뿐만 아니라 보안에 관련하여, 결제 주장 금액이 실 결제 금액과 다를때도 EXCEPTION으로 처리하였다.
이와 같이, PORTONE에게 결제 취소 요청을 보낸다.
결제 취소 요청을 보내는 경우는
1. 사용자가 1000원을 결제하고, 2000원을 결제했다고 속일때(XSS 공격 등)
2. MEMBER CONTAINER의 X-LOCK으로 인해, 이미 결제된 상품이라는 알람이 뜰때
3. MEMBER CONTAINER의 내부 문제로 인하여, SERVER ERROR가 뜰때
이 경우를 모두 각각 잡았다 .
정렬 순서가 조금 이상하지만, 확인해보면
1. 결제를 진행했다. (지금은 극단적인 예시로 4월 18일에 결제를 진행하였지만, 우리는 금액 차만큼 결제를 진행하기 때문에 이런 경우는 나올 수는 없다)
2. 사용자가, 1000원을 결제하고 2000원이라 요청했다. -> DENIED. (DEINED된 날짜는 5/3/19:24:56)
3. 사용자가 잘 결제를 요청하였지만.. MEMBER CONTAINER에서 문제가 생겼다
(XLOCK으로 인해 이미 구매된 상품이든, 혹은 서버 오류든) -> CANCELLED로 표현한다.
셋 모두, PORTONE에 결제 취소를 보낸 이후 해당 정보를 우리 프로젝트 서버 DB에 저장한다!
'프로젝트 > 리팩토링' 카테고리의 다른 글
테스팅 1. 멀티 쓰레드 환경 (0) | 2024.05.03 |
---|---|
리팩토링 4 - WEBFLUX (0) | 2024.04.28 |
리팩토링 3 - JPA 추상층 변경 (0) | 2024.04.19 |
리팩토링 2 - 결제 검증과, XSS 등에 대한 방어 테스트 (1) | 2024.04.19 |
코드 리팩토링 1 - 코드 정리, 가독성 증가 (0) | 2024.04.18 |