Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

14조 코드리뷰 5회차 #69

Merged
merged 1 commit into from
Nov 8, 2024
Merged

14조 코드리뷰 5회차 #69

merged 1 commit into from
Nov 8, 2024

Conversation

rbm0524
Copy link
Contributor

@rbm0524 rbm0524 commented Nov 1, 2024

📌 관련 이슈

✨ PR 내용

9주차 개발사항 적용했습니다.

궁금한점


1. 트랜잭션 분리

@Service
@Slf4j
@RequiredArgsConstructor
/** 결제 승인 서비스 */
public class PaymentConfirmService {

	private final TossPaymentsClient tossPaymentsClient;

	private final PaymentValidationService paymentValidationService;
	private final PaymentStatusUpdateService paymentStatusUpdateService;
	private final PointUpdateService pointUpdateService;

	@Transactional
	public PaymentConfirmationResponse confirm(PaymentConfirmRequest request) {
		// 1. 결제 상태 변경 (준비 -> 실행 중)
		paymentStatusUpdateService.updatePaymentStatusToExecuting(request.orderId(), request.paymentKey());
		// 2. 결제 유효성 검사
		paymentValidationService.validate(request.orderId(), BigDecimal.valueOf(request.amount()));
		// 3. 결제 승인 요청
		PaymentConfirmationResponse response = tossPaymentsClient.confirmPayment(request);
		// 4. 승인 결과에 따른 결제 상태 업데이트
		paymentStatusUpdateService.updatePaymentStatus(new PaymentStatusUpdateCommand(request.paymentKey(), request.orderId(), response.paymentStatus()));
		// 5. 포인트 충전
		pointUpdateService.increasePoint(request.orderId());
		return response;
	}

}

confirm 메소드에서 하나의 트랜잭션으로 5개의 로직이 수행될 때 “결제 상태 변경”과 같은 부가기능의 실패로 결제 승인에 성공하였음에도 DB에 올바르게 기록되지 못하는 상황을 방지하기 위해 트랜잭션을 분리할 수 있나요?

현재 결제 승인 내부 로직 전체를 한 트랜잭션으로 수행 중인데 여기서 수행되는 몇몇의 기능은 별도의 트랜잭션에서 수행되도록 구현하고 싶은데 어떤 방법이 좋을지 궁금합니다!

2. 카카오 로그아웃

카카오 로그아웃 방식
  1. 서비스 토큰만 만료
  • 장점: 간편하다
  • 단점: 로그아웃하고 다시 로그인할 때 바로 로그인되버려서 계정을 못 바꾼다
  1. 카카오 로그아웃
  • 요청: 액세스토큰(카카오의)
  • 응답: 사용자 카카오 아이디
  • 카카오 액세스토큰을 만료시킨다
  • 서비스토큰 만료는 별도로 구현
  1. 카카오 계정과 함께 로그아웃
    -요청: 앱 키, 리다이렉트 url (서비스로그아웃할)
    -응답: 별도로 없음
  • 여기서 카카오 계정과 함께 로그아웃은 요청으로 보내는 거에 사용자 관련 내용이 없는데 어떻게 사용자를 식별에서 로그아웃을 시키는지 알기 어려웠습니다. 이에 대한 멘토님의 도움이 필요합니다,,,
  • 저의 추측: 카카오와 관련된 사용자 정보가 쿠키로써 브라우저에 저장되어 있어서 그걸 활용

구현에 어려움이 있는 것은 아니나 3번 카카오 계정과 함께 로그아웃 방식에 대해서 완벽히 이해하지 못 해 멘토님께 도움을 얻고 싶어 질문드립니다!

* feat: SimpleJpaXXXRepository 추가

* feat: JpaProductRepository 추가

* feat: JpaPaymentOrderRepository 추가

* feat: JpaPaymentEventRepository 추가

* feat: 멱등성 키 생성기 구현

* feat: 결제 준비 DTO 구현

* feat: 결제 주문 응답 DTO 구현

* feat: 결제 준비 기능 구현

* test: PaymentDatabaseHelper 추가

* test: JpaDatabaseCleanup 추가

* test: JpaPaymentDatabaseHelper 추가

* test: test 설정 파일 추가

* test: 결제 준비 기능 테스트 추가

- 결제 준비에 대한 정상 케이스
- 중복 결제 준비 요청에 대한 예외 발생 케이스

* feat: application.yml data.sql 수행 설정

* feat: data.sql 데이터 추가

* chore: build.gradle 스프링 시큐리티 의존성 제거

* feat: 결제 Repository 빈 등록

* feat: PaymentController 결제 준비 엔드포인트 구현

* feat: Api 응답 본문 구조 선언

* feat: 결제 주문 엔티티와 상품 연관관계 삭제

* feat: 결제 상태에 description 필드 추가

* feat: Entity 구현

* feat: Domain 구현

* feat: Mapper 구현

* feat: ProductRepository 추가

* feat: PaymentOrderRepository 추가

* feat: PaymentEventRepository 추가

* feat: SimpleJpaXXXRepository 추가

* feat: JpaProductRepository 추가

* feat: JpaPaymentOrderRepository 추가

* feat: JpaPaymentEventRepository 추가

* feat: 멱등성 키 생성기 구현

* feat: 결제 준비 DTO 구현

* feat: 결제 주문 응답 DTO 구현

* feat: 결제 준비 기능 구현

* test: PaymentDatabaseHelper 추가

* test: JpaDatabaseCleanup 추가

* test: JpaPaymentDatabaseHelper 추가

* test: test 설정 파일 추가

* test: 결제 준비 기능 테스트 추가

- 결제 준비에 대한 정상 케이스
- 중복 결제 준비 요청에 대한 예외 발생 케이스

* feat: application.yml data.sql 수행 설정

* feat: data.sql 데이터 추가

* feat: 결제 Repository 빈 등록

* feat: PaymentController 결제 준비 엔드포인트 구현

* feat: Api 응답 본문 구조 선언

* style: 파일 끝 빈 줄 추가

* feat: DTO record로 변경

* rename: package 이름 수정

memebr -> member

* style: 오타 수정

* rename: 오타 수정

* chore: spring security 의존성 제거

사용하지 않음

* style: 코드 린트 적용

* style: 코드 린트 적용

* feat: application-test.yml 누락된 설정 추가

* feat: 애플리케이션 컨텍스트 로드 테스트 test 프로파일 활성화

* test: 결제 준비 테스트 유지보수

DTO 가 record 타입으로 변경됨에 따른 수정

* feat: 주문 상세 정보 생성 dto 작성

* feat: OrderDetailServcie 생성

주문 상세 정보 생성 메서드만 작성
추후 RUD도 제작 예정

* feat: OrderDetailController 생성

우선적으로 주문 생성만 만들어둠

* fix: member패키지 오타 수정 적용 및 spot 엔티티 필드 명 변경 적용

* feat: swagger config 작성

* feat: swagger 의존성 추가

* style: spotless 적용

* chore: build.gradle 버전 변수 추출 및 spotless 설정 변경

spotless 들여쓰기가 공백 2자에서 4자로 적용되도록 수정

* feat: BaseEntity 추가

* feat: AuditorProvider 구현

* feat: 영속성 설정 클래스 추가

* feat: 애플리케이션 실행 클래스 @EnableJpaAuditing 제거

PersistenceConfig 에서 적용되어 중복 제거

* feat: 카카오 로그인 구현

* refactor: 인텔리제이 마지막 빈 줄 설정 옵션 적용

* refactor: 불필요한 어노테이션 제거

* refactor: RestClient Bean으로 등록 후 Autowired 적용

* refactor: 구체적인 버전은 따로 변수로 추출해서 한 곳에서 관리

* refactor: 불필요한 어노테이션 제거

Json 필드 이름과 KakaoAccount 객체의 필드 이름이 같음

* refactor: @requiredargsconstructor 적용

생성자 생략 가능

* refactor: 정적 팩토리 메서드 네이밍 방식 반영

* feat: swagger config 작성

* feat: swagger 의존성 추가

* feat: Soft delete를 위해 isDeleted 속성 추가

* refactor: isDeleted가 false인 것만 조회하도록 수정

* refactor: isDeleted가 false인 것만 조회하도록 수정

* refactor: isDeleted 추가

* refactor: BaseEntity 상속하도록 수정

* refactor: createdAt, updateAt 필드 추가

* feat: ENUM 타입의 category 추가

* refactor: category의 타입을 Category(ENUM 클래스)로 변경

* feat: ENUM 클래스의 converter에 필요한 CodedEnum 인터페이스 작성

* feat: ENUM 클래스의 converter 작성

* style: 코드 컨벤션 수정

* style: camel case로 변경

* refactor: setter로 변경하던 isDeleted를 delete와 restore 메서드로 변경

* refactor: dirty checking하므로 save가 필요 없어서 삭제

* fix: Converter 어노테이션 붙임

* feat: 결제 주문 엔티티와 상품 연관관계 삭제

* feat: 결제 상태에 description 필드 추가

* feat: Entity 구현

* feat: Domain 구현

* feat: Mapper 구현

* feat: ProductRepository 추가

* feat: PaymentOrderRepository 추가

* feat: PaymentEventRepository 추가

* feat: SimpleJpaXXXRepository 추가

* feat: JpaProductRepository 추가

* feat: JpaPaymentOrderRepository 추가

* feat: JpaPaymentEventRepository 추가

* feat: 멱등성 키 생성기 구현

* feat: 결제 준비 DTO 구현

* feat: 결제 주문 응답 DTO 구현

* feat: 결제 준비 기능 구현

* test: PaymentDatabaseHelper 추가

* test: JpaDatabaseCleanup 추가

* test: JpaPaymentDatabaseHelper 추가

* test: test 설정 파일 추가

* test: 결제 준비 기능 테스트 추가

- 결제 준비에 대한 정상 케이스
- 중복 결제 준비 요청에 대한 예외 발생 케이스

* feat: application.yml data.sql 수행 설정

* feat: data.sql 데이터 추가

* feat: 결제 Repository 빈 등록

* feat: PaymentController 결제 준비 엔드포인트 구현

* feat: Api 응답 본문 구조 선언

* style: 파일 끝 빈 줄 추가

* feat: DTO record로 변경

* rename: package 이름 수정

memebr -> member

* style: 오타 수정

* rename: 오타 수정

* style: 코드 린트 적용

* style: 코드 린트 적용

* feat: application-test.yml 누락된 설정 추가

* feat: 애플리케이션 컨텍스트 로드 테스트 test 프로파일 활성화

* test: 결제 준비 테스트 유지보수

DTO 가 record 타입으로 변경됨에 따른 수정

* fix: OrderDetail 엔티티 수정

팀원들과 회의 후 해당 엔티티 구조를 수정하였고, OrderParticipant는 필요가 없다고 판단

* remove: OrderParticipant 삭제

* remove: OrderParticipant 레포지토리 삭제

* refactor: OrderDetail 수정된 엔티티에 맞게 리팩토링

* fix: 충돌 해결

* feat: PaymentOrderRepository 결제 최종 금액 계산 구현

* refactor: JpaPaymentOrderRepository 조회 실패 시, 발생할 예외 구체화

IllegalArgumentException -> NoSuchElementException

* feat: 결제 유효성 검사 구현

* style: PaymentValidationServiceTest 오타 수정

* feat: Mapstruct 사용을 위한 의존성 추가

* feat: Controller 계층 DTO 작성

* feat: Mapstruct를 이용해 SpotMapper 생성

* refactor: 이름 수정

* feat: SimpleSpotRepository를 가지는 Repository 계층 생성

* refactor: Controller 계층의 Dto를 반환하도록 수정, Service 계층의 Dto를 인자로 넘기도록 수정

* refactor: servicedto 패키지로 이동, accessLevel 조정

* refactor: 매핑 방식 변경

* feat: Member의 PK를 참조하도록 수정

* refactor: 조회 메서드 readOnly로 변경

* style: spotless 적용

# Conflicts:
#	src/main/java/com/ordertogether/team14_be/memebr/persistence/entity/Member.java
#	src/main/java/com/ordertogether/team14_be/payment/domain/PaymentEvent.java
#	src/main/java/com/ordertogether/team14_be/payment/domain/PaymentOrder.java
#	src/main/java/com/ordertogether/team14_be/payment/domain/PaymentOrderStatus.java
#	src/main/java/com/ordertogether/team14_be/payment/domain/Product.java
#	src/main/java/com/ordertogether/team14_be/spot/controller/SpotController.java
#	src/main/java/com/ordertogether/team14_be/spot/dto/SpotDto.java
#	src/main/java/com/ordertogether/team14_be/spot/entity/Spot.java
#	src/main/java/com/ordertogether/team14_be/spot/repository/SpotRepository.java
#	src/main/java/com/ordertogether/team14_be/spot/service/SpotService.java

* feat: 카카오 로그인 구현

* refactor: @requiredargsconstructor 적용

생성자 생략 가능

* feat: PaymentOrder 와 PaymentEvent 연관관계 추가

* feat: 결제 상태에 description 필드 추가

* feat: Domain 구현

* rename: package 이름 수정

memebr -> member

* style: 전역 상수변수 같은 경우에는 변수명을 대문자로 사용

* refactor: jwt에 사용자 정보를 담지 않음

email 대신 사용자의 아이디(pk)를 담음

* refactor: 생성자 주입방식 하나로 통일, @Autowired 지양

* refactor: Enum의 이름을 그대로 반환하도록 수정

* feat: 반경 n미터 내 Spot 조회하기 작성

* feat: 반경 n미터 내 Spot들만 처리해서 반환하는 메서드 작성

* feat: 최대/최소 경도, 위도 내에 해당하는 Spot을 반환하는 메서드 작성

* feat: 최대/최소 경도, 위도 내에 해당하는 Spot을 반환하는 쿼리 작성

* feat: SpotModifyRequest와 SpotDto를 매핑하는 메서드 추가

* refactor: NotNull로 Null 방지

* feat: ErrorResponse 정의

* feat: ErrorCode 정의

* feat: id에 해당하는 Spot이 없는 경우 Exception 정의

* feat: SpotExceptionHandler 작성

* refactor: JwtUtil Spring Bean 제거

* refactor: util 클래스는 상속이 불가능하게 final 설정

* refactor: 토큰 재료를 일반적인 파라미터명으로 변경

* refactor: db 관련 작업 트랜잭션 추가

* refactor: EXPIRE_TIME은 �애플리케이션 설정(application.yaml)으로 변경

* refactor: 카카오 관련 요소 한 곳(KakaoProperties)에서 관리

* refactor: jwt를 사용자 아이디를 가지고 생성

* fix: 프로그램 수행 가능하도록 함

* 7주차 weekly 병합 (#56)

* fix: 프로그램 수행 가능하도록 함

* fix: 안 올라간 파일..

* feat: 토큰 해독 메서드 구현

* feat: 로그인 어노테이션 구현

* feat: 멤버 조회 수정 삭제 구현

* feat: 회원 추가정보 등록 후 회원가입

* fix: 로그인 에러 해결

* style: 안 쓰는 메서드 및 주석 제거, 파일 깔끔하게!

* refactor: 회원 수정 db 재저장

* test: 회원 API 테스트코드 작성

* feat: 결제 파트 누락된 파일 추가

* refactor: 트랜잭션 변경 및 readOnly 적용

* feat: 전역에러핸들러 작성

* refactor: 클라이언트는 멤버아이디를 모른다.. 토큰 사용..

* refactor: 매직리터럴대신 HttpHeaders.AUTHORIZATION 사용

---------

Co-authored-by: westzeroright <[email protected]>
Co-authored-by: westzeroright <[email protected]>

* feat: cors 설정

* refactor: Value를 private final로 설정하고 생성자 주입방식을 사용

* refactor: 중복된 메서드 modifyMemberInfo 제거

* refactor: 트랜잭션 추가

* refactor: 메서드명은 행위를 나타내도록 동사로 시작 loginKakaoUser

* refactor: esponseEntity, HttpStatus, redirect등을 Controller(Web 계층)로 옮김

* refactor: 사용하지 않은 메서드 및 파일 제거

* feat: 의존성 geohash 추가

* refactor: 반지름 삭제

* refactor: geoHash, deadlineTime 추가

* feat: geoHash를 통해 반경 n미터 spot 조회하는 기능 작성

* feat: geoHash 기준으로 Spot 찾기 추가

* refactor: geoHash, deadlineTime(마감시간) 추가

* refactor: deadlineTime(마감시간) 추가

* fix: 중복 메서드 제거

* refactor: 줄바꿈 변경

* feat: 의존성 geohash 추가

* refactor: 반지름 삭제

* refactor: geoHash, deadlineTime 추가

* feat: geoHash를 통해 반경 n미터 spot 조회하는 기능 작성

* feat: geoHash 기준으로 Spot 찾기 추가

* refactor: geoHash, deadlineTime(마감시간) 추가

* refactor: deadlineTime(마감시간) 추가

* refactor: 줄바꿈 변경

* feat: API 응답 형식 필드 final 키워드 추가

* feat: API 응답 형식 생성 메서드 추가

* feat: 더미 데이터에 회원 데이터 추가

* style: 결제 준비 서비스 검증 메서드 변수명 수정

* feat: PaymentEventEntity paymentKey 필드 @nullable 제거

결제 승인 요청 전까지 paymentKey 를 알 수 없음

* feat: 결제 승인 프로세스 예시 페이지 구현

* feat: 포인트 충전 기능 구현

* feat: 결제 주문 저장소 빈 등록 시, 주입될 repo 추가

* feat: PaymentEventRepository 결제 상태 변경 기능 구현

* feat: 결제 상태 변경 기능 구현

* test: PaymentDatabaseHelper 더미 데이터 생성 기능 추가

* feat: 결제 유효성 검사 기능 구현

* feat: TossPayments 응답 DTO 생성

- 결제 승인 응답
- 결제 실패 응답

* feat: TossPaymentsClient 구현

* feat: 결제 승인 DTO 구현

* feat: 결제 승인 기능 구현

* test: 테스트 코드 유지보수

- PaymentEvent 최초 저장 시, PaymentKey 값이 null 이되는 것을 반영

* fix: PaymentEventMapper 도메인 변환 시, paymentOrders 값이 채워지지 않던 버그 수정

* feat: PaymentViewController 추가

* feat: application.yml application-test.yml toss 설정 추가

* rename: PointUpdateService -> PointManagementService

* feat: 포인트 충전 기능 구현

* feat: 결제 승인 기능 구현

* rename: PointUpdateService -> PointManagementService

* feat: 카카오 로그인 구현

* feat: 포인트 충전 기능 구현

---------

Co-authored-by: 나제법 <[email protected]>
Co-authored-by: 나제법 <[email protected]>
Co-authored-by: ajy9851 <[email protected]>
Co-authored-by: westzeroright <[email protected]>
Co-authored-by: westzeroright <[email protected]>
Co-authored-by: ajy9851 <[email protected]>
@leaf-upper
Copy link
Contributor

안녕하세요~ 시험이 마무리 되신지 별로 안되셨을텐데요, 5주차 프로젝트 진행하시느라 고생많으셨습니다~!
몇가지 질문주신부분에 대해서 제가 생각하는 부분을 답변을 드릴게요.

1. 트랜잭션 분리

결제 과정이 웹페이지에서는 굉장히 쉽게 이뤄지는것 같지만 백엔드 서비스 개발 구현 관점에서는 복잡한 부분이 많은것 같아요
질문 주신 부분도 어려운 부분중 하나인데요~
결제 승인이 되었더라도, 서비스 DB에 올바르게 기록되지 않는 상황이 간혹가다 발생할수 있습니다. 대부분의 케이스는 네트워크 오류로 인해서 그런 상황이 종종 발생해요.
일단 질문 주신 부분의 "부가기능에 대한 트랜잭션 분리"는 여러가지 방법이 있을 수 있습니다. 가장 쉬운 방법은 트랜잭션 전파수준 (Propagation)을 변경하여, 부가기능이 실패해서 롤백되더라도, 주요기능은 커밋하실 수 있습니다.
두번째는 메세징 큐 혹은 비동기 이벤트를 이용한 처리 방식인데요, 결제 Event 혹은 메세지를 발행하고, 이 메세지를 처리하는 Handler 혹은 Consumer 애플리케이션을 둬서, 로직을 분리시킬 수 있습니다.

질문 주신 부분에 대한 답변은 위처럼 드릴 수 있겠지만, 트랜잭션을 분리한다고 하더라도 결제 상태가 불일치하는 케이스가 생기기 마련입니다.
그래서 결제 시스템에서는 배치 애플리케이션을 통해 결제 상태의 정합성을 맞춰가는 과정이 필요합니다.

토스 페이먼츠의 결제 시스템을 연동하신다면, 토스페이먼츠에서 제공하는 결제 조회 API (일단위, 시간단위 혹은 분단위로까지 가능합니다.)
를 통해서 토스에서 결제한 내역과 우리가 결제한 내역의 상태가 서로 일치하는지 체크하고, 불일치한다면 이를 어떻게 처리해야할지도 고민이 필요합니다.

결제는 데이터 정합성이 100% 맞아야하는 서비스의 중요한 시스템인만큼 위 답변에 대해서도 좋은 참고가 되셨으면 좋겠습니다.

2. 카카오 로그아웃

여기서 말하는 로그아웃은 결국 사용자의 액세스토큰을 만료시키는 작업을 말하는것 같아요. 질문 주신 부분은 카카오 로그아웃이 아닌,
"카카오 계정과 함께 로그아웃" 기능으로 이해했습니다. 카카오 디벨로퍼스에서의 문서를 읽어봤을때 "카카오 계정과 함께 로그아웃은" 사용자가 카카오 소유의 페이지로 이동하여, 카카오 서비스 자체에서 로그아웃을 하는 기능을 말하는것 같은데요,
모든 서비스의 로그인과정이 그러하듯, 카카오 또한 마찬가지로 관련된 사용자를 식별하기 위해 필요한 정보가 (쿠키 혹은 세션) 브라우저에 남아있기 때문에 이를 이용해 카카오에서 로그아웃 시킬 수 있을것 같습니다.
결론적으로는 추측해주신게 맞는것 같아요.

추가적으로 궁금하신 사항있으시면 말씀부탁드려요~

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frontend와 Backend서버간 Origin이 서로 달라서 CORS 설정을 해주신것 같아요.
서로 같은 Origin이 되도록 웹 서버 (NGINX) 를 하나 두고, 이를 통해 FE의 파일들과, BE의 API를 제공하면 CORS 헤더 없이도 문제를 해결할 수 있을까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호.. nginx를 활용해서 해결할 수도 있는거였군요,, 좋은 방법 알려주셔서 감사합니다! nginx통해서 https 통신을 해보려고 했는데 이 과정 중에서 적용해보겠습니다..!


@Service
@RequiredArgsConstructor
public class PointManagementService {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PointManagementService, PointUpdateService는 완전히 같은 코드 인것 같아서 중복제거를 위해서 한가지만 사용하면 좋을것 같습니다.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PoinUpdateService -> PointManagementService 로 이름을 변경했는데 두 파일이 모두 들어간것 같네요 ㅜㅜ


private void validateObjectsNonnull(
String paymentKey, String orderId, PaymentStatus paymentStatus) {
Objects.requireNonNull(paymentKey, "paymentKey 가 null 인 결제의 상태 변경은 불가능합니다.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍

@RequiredArgsConstructor
public class TossPaymentsClient {

private final RestClient tossRestClient;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최신기술이네요~

Copy link
Contributor

@leaf-upper leaf-upper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍
이전보다 코드의 가독성이 좋아진것 같은기분이 드네요~
너무 고생많으셨습니다!
마지막 1주차 남았는데요! 항상 마지막에 잘 마무리하는게 중요하더라구요~
남은 1주차 화이팅입니다.

@westzeroright
Copy link
Contributor

멘토님 답변감사드립니다! 남은 1주차 화이팅해보겠습니다!!

@nove1080
Copy link
Contributor

nove1080 commented Nov 4, 2024

안녕하세요~ 시험이 마무리 되신지 별로 안되셨을텐데요, 5주차 프로젝트 진행하시느라 고생많으셨습니다~! 몇가지 질문주신부분에 대해서 제가 생각하는 부분을 답변을 드릴게요.

1. 트랜잭션 분리

결제 과정이 웹페이지에서는 굉장히 쉽게 이뤄지는것 같지만 백엔드 서비스 개발 구현 관점에서는 복잡한 부분이 많은것 같아요 질문 주신 부분도 어려운 부분중 하나인데요~ 결제 승인이 되었더라도, 서비스 DB에 올바르게 기록되지 않는 상황이 간혹가다 발생할수 있습니다. 대부분의 케이스는 네트워크 오류로 인해서 그런 상황이 종종 발생해요. 일단 질문 주신 부분의 "부가기능에 대한 트랜잭션 분리"는 여러가지 방법이 있을 수 있습니다. 가장 쉬운 방법은 트랜잭션 전파수준 (Propagation)을 변경하여, 부가기능이 실패해서 롤백되더라도, 주요기능은 커밋하실 수 있습니다. 두번째는 메세징 큐 혹은 비동기 이벤트를 이용한 처리 방식인데요, 결제 Event 혹은 메세지를 발행하고, 이 메세지를 처리하는 Handler 혹은 Consumer 애플리케이션을 둬서, 로직을 분리시킬 수 있습니다.

질문 주신 부분에 대한 답변은 위처럼 드릴 수 있겠지만, 트랜잭션을 분리한다고 하더라도 결제 상태가 불일치하는 케이스가 생기기 마련입니다. 그래서 결제 시스템에서는 배치 애플리케이션을 통해 결제 상태의 정합성을 맞춰가는 과정이 필요합니다.

토스 페이먼츠의 결제 시스템을 연동하신다면, 토스페이먼츠에서 제공하는 결제 조회 API (일단위, 시간단위 혹은 분단위로까지 가능합니다.) 를 통해서 토스에서 결제한 내역과 우리가 결제한 내역의 상태가 서로 일치하는지 체크하고, 불일치한다면 이를 어떻게 처리해야할지도 고민이 필요합니다.

결제는 데이터 정합성이 100% 맞아야하는 서비스의 중요한 시스템인만큼 위 답변에 대해서도 좋은 참고가 되셨으면 좋겠습니다.

오 배치 애플리케이션을 통해 정합성을 맞추는 부분은 생각하지 못했는데 말씀 감사합니다!
이번 프로젝트에 배치 서버를 구축하긴 힘들겠지만 프로젝트가 종료된 후에 보다 완성도 높은 결제 시스템을 위해 만들어보겠습니다~

@rbm0524 rbm0524 merged commit c47d15e into Review Nov 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants