결과를 모르는 결제의 복구가 확정 못 한 건에 막혀 뒤를 5분 동안 한 건도 풀지 못했다
목차
결과를 모르는 결제의 복구 배치는 확정하지 못한 건이 앞자리를 차지하면 그 뒤를 풀지 못했습니다. PG가 “진행 중”이라고 답하는 건 100개가 가장 오래된 자리에 있자, 그 뒤의 500건은 5분 동안 한 건도 풀리지 않았습니다. 확정하지 못한 건의 다음 시도를 1분, 2분, 4분, 8분 뒤로 미루자 같은 500건이 60초에 풀렸습니다. 막힌 건이 없을 때는 50초였습니다.
개요
결제 승인 요청이 PG에서 시간 초과로 끝나면 결제는 성공도 실패도 아닌 미확정(UNKNOWN) 상태로 남습니다. PG 쪽에서는 승인이 끝났을 수도 있어서 우리 마음대로 실패로 적으면 안 됩니다. 그래서 복구 배치가 주기마다 미확정 결제를 읽어 PG 조회 API로 실제 상태를 묻고 확정합니다.
복구 쿼리는 “1분 넘게 미확정인 결제”를 청크(기본 500건)만큼 읽습니다. 앞선 측정은 PG 쪽이 전부 승인인 경우만 재서 “진행 중인 건은 다음 주기로 미뤄진다”고만 적었습니다. 미뤄진 건이 다음 주기에 어디에 서는지는 재지 않았습니다.
무엇이 막히나
PG가 “진행 중”이라고 답하거나 조회가 실패한 결제는 미확정으로 남습니다. 복구 쿼리의 조건은 다음 주기에도 똑같으니 같은 건이 같은 자리에서 다시 읽힙니다. 이런 건이 청크만큼 쌓이면 청크가 전부 그 건들로 차고 뒤의 결제는 차례가 오지 않습니다.
세 정책을 비교했습니다.
| 정책 | 읽는 순서 |
|---|---|
unordered(이전) | 정렬 없음 |
oldest | 요청 시각이 오래된 순을 명시 |
backoff | 확정하지 못한 건은 다음 시도를 1·2·4·8분 뒤(상한 10분)로 미루고 때가 된 것 중 오래된 순 |
어떻게 쟀나
가짜 PG가 특정 접두어의 결제 키에 늘 “진행 중”이라고 답하게 했습니다. 그런 결제 100건을 10분 전 시각으로, 나머지 500건을 5분 전 시각으로 넣었습니다. 둘 다 복구 대상 조건(1분 초과)을 넘습니다. 복구 주기는 5초, 청크는 50건이고 결제 표를 2초마다 읽었습니다.
| 정책 | 풀리는 500건 해소 | 막힘 없을 때 대비 | 다시 조회된 막힌 건 | 막힌 건 시도 횟수 |
|---|---|---|---|---|
| 막힌 건 없음 | 50초 | 1.00배 | 해당 없음 | 해당 없음 |
unordered | 5분 안에 0건 | 해당 없음 | 50/100 | 0~59 |
oldest | 5분 안에 0건 | 해당 없음 | 50/100 | 0~59 |
backoff | 60초 | 1.20배 | 100/100 | 3 |
판정 기준은 측정 전에 정했습니다. 막힘 없을 때의 1.5배 안에 풀고 막힌 건마다 한 번 이상 다시 조회해야 통과입니다. backoff만 통과해서 기본값으로 했습니다.
순서를 바꿔서는 풀리지 않았다
unordered와 oldest의 결과가 완전히 같았습니다. (status, requested_at) 인덱스 덕에 정렬을 걸지 않아도 이미 오래된 순으로 읽히고 있었습니다. 막힌 원인은 확정하지 못한 건이 매 주기 앞자리를 다시 차지하는 것이었습니다.
굶는 쪽도 하나가 아니었습니다. 막힌 100건 중 청크 밖의 50건도 5분 동안 한 번도 PG에 다시 묻지 않았습니다. 그 사이 PG가 승인을 끝냈어도 우리는 모릅니다. 청크 안의 50건은 5초마다 같은 질문을 59번 했습니다.
backoff가 늦은 10초는 첫 두 주기가 막힌 100건을 한 번씩 묻고 미루는 데 쓰였기 때문입니다. 그 뒤로는 주기마다 50건씩 풀렸습니다. 막힌 건은 1분 뒤와 그 2분 뒤에 다시 물어 5분 동안 3번씩 조회됐습니다.
정리
- 확정하지 못한 시도는 결제 행에 횟수와 다음 시도 시각으로 남깁니다. 복구 쿼리는 다음 시도 시각이 지난 것만 읽습니다
- PG 조회가 실패한 건도 같이 미룹니다. 앞자리를 차지하는 것은 “진행 중”과 같기 때문입니다
- 대가는 막힌 건의 확정이 최대 10분 늦어질 수 있다는 것입니다. 오래 미확정인 건은 가장 오래된 미확정의 나이를 보는 알림이 따로 잡습니다
- 미루는 간격(1·2·4·8분, 상한 10분)은 재서 고른 값이 아닙니다. 실제 PG가 “진행 중”을 얼마나 오래 답하는지는 모릅니다
댓글
댓글 수정/삭제는 GitHub Discussions에서 가능합니다.