Skip to content
isdnetworks
Go back

없는 레코드를 영원히 기다린다

한 처리 건이 사흘째 대기 상태로 멈춰 있다는 이야기가 들어왔다. 실패한 것도 아니고 끝난 것도 아닌 채였다.

Table of contents

Open Table of contents

증상 — 사흘째 대기

처리 커맨드의 매핑 함수를 열었다.

private function mappingOption($order)
{
    $item = $this->findReturnItem($order->origin_item_id);

    if (!$item) {
        return ['result' => 'pending'];
    }
    ...
}

findReturnItem 이 빈 값을 내면 그대로 대기를 반환한다.

이 건은 return_items 쪽 대응 항목이 애초에 없는 상태였다. $item 이 나중에 생기기를 기다리는 구조라서 끝이 없었다.

원인 — 시도 횟수가 안 늘었다

대기로 빠지는 자리를 더 봤다.

if ($result['result'] === 'pending') {
    $order->status = 'pending';
    $order->save();
    return;              // 시도 횟수 증가 없음
}

$order->statuspending 으로 바꾸고 시도 횟수는 건드리지 않은 채 빠져나간다.

보통은 시도가 쌓이면 한도를 넘어 실패로 빠지고 그때 알림이 나가거나 목록에 잡힌다. 여기서는 한도에 닿을 길이 없으니 아무 신호 없이 영원히 대기였다.

전체 흐름 — 왜 없는지의 경위

대응 항목이 왜 없는지 이력을 역추적했다.

1. 교환 접수  →  새 항목 생성
2. 그 항목이 결제 취소됨
3. 외부가 재교환 가주문을 다시 만듦
4. 새 항목에 대한 클레임이 없음
5. 매핑 실패 → 영원히 대기

두 번째 줄의 결제 취소 가 관건이었다.

교환으로 생긴 항목이 취소되면 거기에 딸린 클레임 도 함께 정리된다. 그 뒤에 외부가 가주문을 다시 만들면 새 항목에는 클레임이 없는 상태로 넘어온다.

검증 — 같은 패턴을 세었다

이 건 하나만인지 확인했다.

대기 상태로 방치      4건 이상
오류 상태            수천 건

대기 쪽에 수개월 방치된 것들이 섞여 있었다.

오류 는 그래도 집계에 잡히는데 대기 는 아무 데도 안 잡힌다. 정체된 건을 만나면 그 항목에 대응하는 레코드가 있는지부터 본다는 순서를 그때 정했다.

SELECT COUNT(*) FROM return_items WHERE order_item_option_id = ?;

COUNT(*) 가 0이면 이 유형이다.

선택지 — 세 가지 해결 방향

수동 해결 방향을 셋으로 정리했다.

① 외부에서 가주문 취소     원인 쪽을 정리한다
② 상태를 오류로 강제 전환  대기에서 빼서 목록에 잡히게 한다
③ 수동으로 레코드 생성     없는 것을 만들어 진행시킨다

이 가장 깨끗하지만 외부 관리 화면에서 해야 한다.

이 가장 위험했다. 실제로 없는 데에는 이유가 있는데 그 이유를 모른 채로 만드는 것이다.

대응 — 보이게 만드는 것이 먼저

를 우선으로 봤다.

① 은 외부 협조가 필요
③ 은 없는 데이터를 만드는 것
② 는 우리 안에서 되고, 보이게 만든다

대기 는 보이지 않는 것이 문제라서 오류 로 바꾸면 최소한 집계에 잡힌다.

대기 라는 말은 곧 될 것이라는 뜻으로 읽힌다. 될 조건이 영영 안 생기는 건이 그 상태로 남아 있으면 그 표시 자체가 거짓 신호다.

근본은 따로 적어 두었다.

대응 레코드 없음

시도 횟수 증가

한도 초과 시 오류로 전환

곧 될 대기와 영영 안 될 대기를 시도 횟수로 가르는 것이다.

몇 번 시도해도 안 되면 그것은 대기가 아니라 문제다. 그 구분이 코드에 없으면 상태 이름이 실제 상황과 어긋난 채로 남는다.

정리


Share this post on:

Previous Post
플래그 하나를 두 기능이 쓴다
Next Post
24시간 멈추면 안 되는 시스템을 맡는다는 것