주문 상태는 Pending인데, 사용자는 결제 안내를 받았다.
결제 시스템을 구현하다 보면 반드시 고려해야 하는 장애 시나리오 중 하나다.
PG에서는 결제가 성공했지만, 주문 서비스 통신 중 네트워크 통신 오류나 PG사에 데이터 전달(Callback)이 실패하면 서비스는 결제 결과를 알지 못한 채 주문 상태를 PENDING으로 유지할 수 있다.
이러한 상황을 이해하기 위해 먼저 일반적인 PG 결제 흐름을 살펴보자.
외부 PG 결제 흐름

1. 사용자는 서비스에 결제를 요청하고, 서비스는 PG사에 결제 요청을 전달한다.
2. PG사는 결제 처리가 완료되면 Callback URL을 통해 결제 결과(성공 또는 실패)를 서비스에 전달한다. 서비스는 전달받은 결과를 기반으로 주문 상태를 변경하거나 후속 비즈니스 로직을 수행한다.
3. 모든 과정이 정상적으로 수행된다면 사용자와 서비스는 동일하게 "결제가 완료되었다."는 상태를 바라보게 된다.
하지만 네트워크 장애나 일시적인 서비스 장애 등으로 전달되지 않는다면 상황은 달라진다. 사용자는 이미 결제 완료 안내를 받았지만, 서비스는 결제 성공 사실을 알지 못해 주문 상태를 PENDING으로 유지하게 된다.
이처럼 사용자와 서비스가 서로 다른 상태를 바라보는 순간, 외부 API 결제 데이터와 주문 간의 데이터 정합성 문제가 발생한다.
외부 API 흐름은 항상 정상적인 동작은 아니다.
PG사의 Callback은 결제 결과를 전달하는 가장 일반적인 방식이지만, 반드시 전달된다는 보장은 없다. 네트워크 장애, Timeout, 일시적인 서버 장애와 같은 이유로 Callback이 유실되거나 지연될 수 있으며, Callback이 정상적으로 전달되더라도 우리 서비스의 장애로 인해 처리하지 못하는 상황도 발생할 수 있다.
이 경우 사용자는 이미 결제 완료 안내를 받았지만, 서비스는 결제 성공 사실을 인지하지 못한다. 결과적으로 내부 시스템에서는 주문 상태가 PENDING으로 남아 있게 되고, 사용자와 서비스가 서로 다른 상태를 바라보는 문제가 발생한다.
만약 PG사에서 결제 상태 조회 API를 제공한다면, 이러한 상황을 복구하기 위해 다음과 같은 방법들을 고려해 볼 수 있다.
사용자 화면에서 주문 PENDING 상태 일 경우 Callback 수신 실패 Polling

사용자에게 결제 완료 화면을 무한정 대기하도록 할 수는 없다. 따라서 주문 상태가 PENDING인 동안 일정 주기로 PG의 결제 상태 조회 API를 호출하는 Polling 방식을 고려할 수 있다.
Polling은 Callback이 일시적인 네트워크 장애나 서버 장애로 유실되더라도, 사용자가 결제 완료 화면에 머무는 동안 결제 상태를 다시 조회하여 주문 상태를 빠르게 동기화할 수 있다. 별도의 운영 개입 없이 단기간의 장애를 즉시 복구할 수 있으며, 결제 직후 사용자에게 최신 주문 상태를 제공할 수 있다는 장점이 있다.
하지만 Polling은 클라이언트에서 수행되는 방식이기 때문에 사용자가 브라우저를 종료하거나 페이지를 이탈하는 순간 더 이상 동작하지 않는다. 즉, 결제가 이미 성공했더라도 사용자의 추가 요청이 없다면 주문 상태는 계속 PENDING으로 남아 있을 수 있다.
결제 시스템은 사용자의 행동과 관계없이 최종적으로 데이터 정합성을 보장해야 한다. 따라서 Polling은 사용자 경험을 개선하는 데에는 효과적이지만, 결제 데이터와 주문 데이터의 최종 정합성을 보장하기 위한 해결책으로는 한계가 있다.
스케줄러를 이용한 결제 상태 보정

Polling과 달리 사용자의 요청에 의존하지 않고, 서버에서 주기적으로 PENDING 상태의 주문을 조회하여 PG의 결제 상태 조회 API를 호출하는 방법도 고려할 수 있다.
스케줄러는 일정 주기마다 미처리 주문을 조회하고 실제 결제 상태를 확인한 뒤, 결제가 완료된 주문은 COMPLETED로 변경하고 필요한 후속 처리를 수행한다. 따라서 사용자가 브라우저를 종료하거나 페이지를 이탈하더라도 서비스가 스스로 미처리 주문을 복구할 수 있으며, 최종적인 데이터 정합성을 보장할 수 있다는 장점이 있다.
반면 스케줄러는 실행 주기에 따라 결제 완료 반영이 지연될 수 있다. 또한 Callback이 정상적으로 전달되어 처리 중인 주문을 스케줄러가 동시에 조회할 수 있기 때문에, 동일한 주문을 중복 처리하지 않도록 멱등성(Idempotency)과 동시성 제어를 반드시 고려해야 한다.
Polling과 스케줄러 활용하기
Polling은 결제 직후 사용자에게 주문 상태를 빠르게 반영하기 위한 방식으로 사용했고 Callback이 지연되거나 유실되는 상황에서도 사용자가 머무는 동안 즉시 상태를 보정하여 사용자 경험을 개선하는 역할을 하는 반면 스케줄러는 사용자 행동과 무관하게 시스템 차원에서 최종 정합성을 보장하기 위해 사용했고 일정 주기로 PENDING 상태의 주문을 조회하고 PG 결제 상태를 기반으로 최종 상태를 확정함으로써, Callback이나 Polling으로 처리되지 못한 케이스까지 보완한다.
결과적으로 두 방식은 동일한 문제를 해결하지만 목적이 다르다. Polling은 “빠른 반영”, 스케줄러는 “최종 보정”이라는 역할로 분리되어 서로를 보완하는 구조로 설계되었다.
결론
결제 시스템에서 데이터 정합성을 완벽하게 보장하는 것은 현실적으로 어렵다. PG Callback은 네트워크 환경이나 외부 시스템 상태에 따라 유실될 수 있고, 이를 100% 신뢰하는 구조는 위험하다.
따라서 중요한 것은 정합성을 “완벽하게 맞추는 것”이 아니라, 최종적으로 비슷하게 동일한 상태로 수렴하도록 설계하는 것이다.
'루퍼스 4기' 카테고리의 다른 글
| 주문 폭주를 막는 대기열, 배치 사이즈는 어떻게 정해지나 (0) | 2026.07.10 |
|---|---|
| 주문 도메인에서 아웃박스 패턴과 polling 스케줄러 도입기 (1) | 2026.07.02 |
| 인덱스 적용부터 반정규화까지, 조회 성능 개선 실험 (0) | 2026.06.19 |
| 루퍼스 4주차 WIL (동시성 문제 해결) (0) | 2026.06.14 |
| 쇼핑몰에서 안전하게 재고 차감하기 (0) | 2026.06.12 |