Skip to content
isdnetworks
Go back

종결 처리가 여러 자리에 걸쳐 있었다

주문을 종결 처리했는데 어떤 화면에서는 여전히 진행 중으로 남아 있었다. 종결이 한 곳의 상태만 바꾸는 것이 아니었다. 그 주문에 걸려 있는 여러 자리를 함께 정리해야 하는 처리였다.

Table of contents

Open Table of contents

무엇이 걸려 있었나

그 주문 번호를 참조하는 곳을 information_schema 로 전부 찾았다.

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'shop' AND column_name IN ('order_no', 'order_id');

order_noorder_id 를 가진 표가 열한 개 나왔고 그중 넷이 종결 시 처리가 필요했다. 그런데 close()ordersorder_tasksettle_target 셋만 하고 있었다.

public function close(int $orderNo): void {
    $this->orders->updateState($orderNo, 'CLOSED');
    $this->tasks->cancelPending($orderNo);
    $this->settle->finalize($orderNo);
    // 알림과 재고가 빠졌다
}

notify_schedulestock_reserve 가 빠져서 그 둘이 주문을 여전히 진행 중으로 취급하니 화면에 그렇게 나온 것이다.

남길 것과 정리할 것

전부 지우면 되는 것도 아니었는데 order_log 는 그대로 남아 있어야 나중에 무슨 일이 있었는지 알 수 있기 때문이다.

그래서 열한 표를 남길 것과 정리할 것으로 갈랐다.

처리 필요
  order_task        진행 중 작업 취소
  notify_schedule   예약 알림 취소
  stock_reserve     예약 해제
  settle_target     확정 또는 제외

처리 불필요
  order_log         이력이므로 그대로 둔다
  order_item        주문 내용이므로 그대로 둔다
  payment           결제 기록이므로 그대로 둔다

종결이라는 한 단어가 자리마다 다른 동작을 뜻하고 있었다.

한 자리에 모으고 묶기

정리해야 할 다섯 동작을 close() 한 곳에 모았다.

public function close(int $orderNo, string $reason): void {
    $this->db->transaction(function () use ($orderNo, $reason) {
        $this->orders->updateState($orderNo, 'CLOSED', $reason);
        $this->tasks->cancelPending($orderNo);
        $this->notify->cancelScheduled($orderNo);
        $this->stock->releaseReserved($orderNo);
        $this->settle->finalize($orderNo);
    });
}

cancelScheduledreleaseReserved 를 더한 다섯이 한 transaction 안에서 돌므로 중간에 실패하면 ROLLBACK 되고 일부만 반영되는 상태가 안 생긴다.

전에는 각 화면이 updateState 만 부르거나 cancelPending 까지만 부르는 식이라 어느 경로로 종결했느냐에 따라 결과가 달랐다. 같은 종결인데 결과가 다른 것이 그 자체로 문제였다. 모으고 나니 어느 경로로 들어와도 같은 상태가 됐다.

검증 — 다른 코드로 확인하기

제대로 정리되는지 확인할 때 close() 를 다시 불러서 확인하면 아무 의미가 없다. 같은 실수가 확인 쪽에도 그대로 들어가기 때문이다.

그래서 확인은 CLOSED 인 주문을 order_task · notify_schedule · stock_reserveJOIN 하는 별도 SELECT 로 만들어서 남아 있는 것이 있는지 직접 찾게 했다. 만드는 코드와 확인하는 코드를 다르게 쓰는 것이 이런 확인의 기본이었다. 실제로 그 조회로 앞서 어긋난 건들을 찾아냈다.

매일 훑고 새 자리를 막기

이미 어긋난 notify_schedulestock_reserve 를 전부 정리한 뒤에 그 SELECTcron 으로 매일 돌게 걸었다. 새로 어긋나는 것이 있으면 그날 알게 된다.

그리고 새 표가 생길 때 close() 에 넣는 것을 잊지 않도록 만들었다. order_no 를 참조하는 표를 새로 만들면 그 목록에 등록하게 하고 등록 안 된 것이 있으면 확인에서 걸린다. 되돌리는 처리도 같은 구조로 만들어서 종결을 취소할 때 대칭이 되게 했다.

정리


Share this post on:

Previous Post
한 축이 아니라 쌍으로 분기한다
Next Post
값 하나를 바꾸면 여러 테이블이 같이 바뀌어야 했다