Skip to content
isdnetworks
Go back

재고를 실시간으로만 맞추려니 어긋난 걸 못 잡았다

주문이 들어오면 재고를 바로 뺀다. 취소되면 되돌린다. 논리는 단순한데 실제 수량이 자꾸 안 맞았다. 창고에서 세어 온 수와 화면 수가 며칠에 한 번씩 어긋났다.

Table of contents

Open Table of contents

재고를 바꾸는 자리가 여럿이었다

차감은 주문 저장과 같은 트랜잭션 안에 있었다.

$this->db->trans_start();

$this->db->insert('order_item', [...]);
$this->db->query(
    "UPDATE stock SET qty = qty - ? WHERE product_no = ?",
    [$qty, $no]
);

$this->db->trans_complete();

trans_starttrans_complete 사이라 주문이 들어가면 stock 도 같이 준다. 문제는 재고를 바꾸는 자리가 여기만이 아니라는 것이었다.

$ grep -rn "UPDATE stock" --include=*.php application/

일곱 군데였다. 주문 저장과 주문 취소와 반품 입고와 관리자 수동 조정과 입고 등록과 교환 처리와 일괄 등록 화면이다.

일곱 곳이 각자 qty 를 더하고 뺀다. 한 군데라도 트랜잭션 밖이면 거기서 어긋난다.

일괄 등록 화면이 그랬다.

foreach ($rows as $r) {
    $this->db->query("UPDATE stock SET qty = qty + ? WHERE product_no = ?", [...]);
}

트랜잭션이 없어서 autocommit 이 켜진 채로 한 줄씩 커밋된다. 200행을 처리하다 중간에 오류가 나면 앞의 것만 반영된 채로 끝나는데 화면에는 실패했다고 나오니 다시 올리고 앞의 것이 두 번 더해진다.

현재 수량만으로는 판단할 수 없었다

일곱 군데를 전부 트랜잭션에 넣어도 남는 것이 있었다. 어긋났다는 것을 알 방법이 없다는 점이다.

stock.qty 라는 숫자 하나만 들고 있으면 그것이 맞는지 판단할 근거가 없다. 값이 틀려도 틀렸다는 것을 알 수 없는 구조였다.

어긋난 것을 창고에서 세어 올 때만 발견했고 그 사이에 며칠이 지나 있었다.

기록으로 남긴 변동

그래서 두 가지를 같이 뒀다. 하나는 변동을 기록으로 남기는 것이다.

CREATE TABLE stock_history (
  history_no INT NOT NULL AUTO_INCREMENT,
  product_no INT NOT NULL,
  diff       INT NOT NULL,
  reason     VARCHAR(20) NOT NULL,
  ref_no     INT NULL,
  reg_date   DATETIME NOT NULL,
  PRIMARY KEY (history_no),
  KEY idx_product_date (product_no, reg_date)
);

qty 를 바꿀 때 stock_historydiffreason 을 같이 남긴다. 같은 트랜잭션 안이다.

다른 하나는 주기적으로 대조하는 것이다.

SELECT s.product_no, s.qty, IFNULL(SUM(h.diff), 0) AS calc
FROM stock s
LEFT JOIN stock_history h ON h.product_no = s.product_no
GROUP BY s.product_no
HAVING s.qty != calc;

현재 수량과 SUM(diff) 가 다르면 어딘가에서 기록 없이 바뀐 것이다.

돌려 보니 12건이 나왔다. 일괄 등록에서 중간에 끊긴 것이 5건이고 관리자가 직접 고친 것이 4건이며 반품 처리에서 기록을 안 남기는 경로가 3건이었다.

세 번째가 코드 문제라 stock_history 를 남기게 고쳤다. 두 번째는 그런 일이 있었다는 것 자체가 확인된 것이고 앞으로 관리자 화면으로 하게 안내했다. 대조가 없었으면 이 세 부류를 구분조차 못 했다.

검증 — 대조가 실제로 잡는지 봤다

새벽에 하루 한 번 돌게 하고 결과가 있으면 목록을 남겼다.

[재고대조 2014-11-06] 불일치 3건
  product 1204: qty=15 calc=18 diff=-3
  product 2871: qty=0  calc=2  diff=-2
  product 3390: qty=44 calc=41 diff=+3

자동으로 고치지는 않게 했는데 qtycalc 중 어느 쪽이 맞는지 프로그램이 판단할 수 없어서 사람이 보고 정한다.

자동으로 맞추면 원인을 못 찾는다. 매일 조용히 맞춰지니 새는 곳이 안 드러난다.

돌려서 0건이 나왔을 때 그것이 정말 안 어긋난 것인지 대조가 아무것도 안 보는 것인지 구분이 안 됐다.

UPDATE stock SET qty = qty + 5 WHERE product_no = 9999;

stock_history 를 건너뛰고 qty 만 바꿔 한 건을 어긋나게 만들었더니 다음 대조에서 그 건이 나왔다. 되돌리고 나서 다시 0건이 됐다.

이걸 해 보기 전까지는 0건이 통과인지 아닌지 알 수 없었다.

정리


Share this post on:

Previous Post
로그에 개인정보가 그대로 있었다
Next Post
알림이 아무도 안 보는 곳으로 갔다