Skip to content
isdnetworks
Go back

상태를 안 바꾸던 컨슈머

(수정됨)

장기 미처리 취소 대기 건을 분석하다가 일부의 상태가 이상한 것을 봤는데, channel_claims.status 는 success 인데 order_cancels.status 는 REQUESTED 로 남아 있었다.

Table of contents

Open Table of contents

조사 — 흐름의 단계 정의

코드를 뒤지기 전에 취소 요청이 들어와서 처리되기까지의 흐름을 단계로 먼저 그렸다.

① 수집이 클레임을 대기 상태로 저장
② 스케줄러가 대기 건을 큐로 전송
③ 컨슈머가 외부 API 호출
④ 성공하면 클레임을 success 로 마킹

클레임이 success 라는 것은 네 번째 단계까지 정상적으로 갔다는 뜻이다. 단계를 먼저 정의해 두니 어디까지 갔는지가 상태값 하나로 확인됐다.

원인 — 빠진 마지막 단계

여기에 다섯 번째 단계가 있어야 했는데 order_cancels.status 를 REQUESTED 에서 COMPLETED 로 전환하는 것이다.

ClaimConsumer 코드를 보니 클레임만 success 로 바꾸고 order_cancels 는 건드리지 않은 채 끝나고 있었다. 그래서 외부 처리는 완료이고 클레임도 성공인데 우리 취소만 요청 상태로 영구히 남는다.

그 상태로 화면에는 취소 대기로 뜨고 입점사는 취소가 안 됐다며 문의를 넣는다. 실제로는 끝난 일인데 우리 기록만 안 끝난 것이라 어느 쪽 말도 틀리지 않았다.

재수집이 안 통하는 이유

재수집하면 상태가 갱신되지 않을까 싶어 수집 코드를 봤다.

if ($existingClaim) {
    // $claim->status = 'ready_v2';   ← 주석 처리
    return;
}

기존 레코드가 있으면 수정 분기로 들어가는데 거기서 상태를 되돌리는 로직이 주석 처리돼 있어 아무 효과가 없다. 게다가 클레임이 이미 success 면 스케줄러가 ready 만 집으므로 그 건을 아예 안 집는다.

즉 재수집으로는 어떤 경우에도 안 풀리는 구조였다. 이걸 미리 확인하지 않았으면 재수집을 몇 번 돌려 보고 왜 안 되는지를 다시 조사했을 것이다.

조치 — 수동 복구와 근본 수정

두 가지 방법이 있었는데 밀린 건들의 클레임을 ready 로 되돌려 컨슈머를 다시 태우는 것과 우리 쪽 기록만 손으로 맞추는 것이다. 뒤쪽을 골랐다. 이유는 외부는 이미 끝났으므로 다시 태우면 취소 요청이 중복으로 나가서다. 대신 status 와 cancelled_at 과 order_items.status 세 값을 UPDATE 로 맞추는 스크립트를 따로 검토받아야 하는 것을 감수했다.

근본 수정은 ClaimConsumer 에 다섯 번째 단계를 추가하는 것이다. 수동 복구는 밀린 것만 치우고 그 뒤로 또 쌓이므로 컨슈머를 안 고치면 같은 복구를 계속 반복하게 된다.

판단 기준 — 책임 경계의 공백

왜 빠졌는지 짐작해 보면 책임 경계가 애매했기 때문인 것 같다. ClaimConsumer 는 외부 호출과 channel_claims 관리가 자기 일이고 order_cancels 는 다른 쪽 일이라고 봤을 수 있다.

문제는 그 다른 쪽이 존재하지 않았다는 점이고 결국 아무도 그 값을 안 바꾼다. 두 시스템에 걸친 흐름에서 마지막 단계가 누구 것인지 정해지지 않으면 그 단계가 통째로 빠지고 양쪽 다 자기 일은 다 했다고 본다.

흐름을 먼저 그린 것이 이 진단에서 유효했다. 단계를 정의하고 각 단계의 증거를 상태값에서 찾으면 빠진 데가 한눈에 드러난다. 코드부터 뒤졌으면 여기도 없고 저기도 없다는 식으로 한참을 헤맸을 것이다.

정리


Share this post on:

Previous Post
WHERE에 들어간 결론
Next Post
제외를 적용하고 센다