결제 완료 처리가 가끔 안 돼서 결제는 됐는데 주문이 미결제로 남는 일이 있었다. 흐름이 우리 화면에서 결제사 화면으로 나갔다가 돌아오는 구조라 그 사이에 무슨 일이 있었는지를 알 수 없었다.
Table of contents
Open Table of contents
돌아오지 못하는 경우들
완료 처리를 브라우저가 돌아오는 길에서만 하고 있었으므로 못 돌아오면 처리가 안 된다. 결제 뒤 브라우저를 닫거나 망이 끊기거나 복귀 요청이 실패하거나 우리 서버가 잠깐 죽어 있는 네 경우가 있었다.
전부 결제는 됐는데 우리만 모르는 상태가 된다. 한 경로에만 의존하는 완료 처리는 그 경로가 실패하는 만큼 그대로 누락이 된다.
서버 경로를 함께 받기
결제사가 서버로 직접 알려 주는 통보 경로가 있어서 그것도 받게 했다. 브라우저가 안 돌아와도 그 경로로 들어온다.
둘 다 받되 어느 쪽이 먼저 와도 되게 하고 이미 처리된 주문이면 그냥 반환하게 했다. 잠금을 걸고 상태를 확인하므로 두 번 와도 한 번만 처리된다.
마지막 안전망
서버 통보도 실패할 수 있으므로 우리가 물어보는 경로를 하나 더 뒀다. 일정 시간이 지나도 준비 상태로 남아 있는 주문을 모아 결제사에 직접 조회한다.
결제된 것으로 나오면 완료 처리하고 통보 누락으로 로그를 남긴다. 이렇게 브라우저 복귀와 서버 통보와 사후 조회 셋 중 하나만 되면 처리되는 구조가 됐다.
통보의 진위 확인
서버 통보는 주소만 알면 누구나 보낼 수 있으므로 서명을 확인했다. 확인하지 않으면 아무나 완료 처리를 시킬 수 있다.
금액도 주문 금액과 대조했는데 서명이 맞더라도 금액이 다르면 거절한다. 밖에서 들어오는 통보는 인증과 값 검증을 둘 다 거쳐야 근거가 된다.
화면과 대조와 실패 기록
브라우저가 돌아왔는데 아직 처리가 안 된 경우에는 확인 중이라는 화면을 보이고 뒤에서 상태를 물었다. 일정 시간 안에 안 되면 확인 중 화면으로 보내서 실패로 보이지 않게 했다.
우리 쪽이 미결제인데 결제사에는 결제된 건이 있는지를 매일 아침 대조했고 처음 돌렸을 때 지난 것 중 열두 건이 나왔다. 실패한 결제도 사유와 원본 응답을 남기게 했더니 사유별 분포가 보였고 가장 많은 것에 맞춰 화면 안내를 고쳤다.
정리
- 흐름이 우리 밖으로 나가면 돌아오는 길을 설계해야 한다
- 브라우저가 안 돌아올 수 있으므로 서버 경로 통보도 받는다
- 둘 다 안 와도 우리가 물어보는 마지막 안전망을 둔다
- 어느 쪽이 먼저 와도 되게 하고 두 번 와도 한 번만 처리한다
- 통보는 서명과 금액을 둘 다 확인한다
- 아직 처리 전이면 기다리는 화면을 보인다
- 매일 대조해서 0이 아니면 본다
- 실패한 결제도 사유를 남겨야 안내를 고칠 수 있다