라벨은 출력됐다. 소포는 출고되지 않았다. 열 번 중 아홉 번, 주문은 API 체인의 어딘가에서 사라진다.
2023년 성수기, 로스앤젤레스의 한 3PL 창고에서 연락이 왔다. 하루 12,000건의 주문을 처리하고 라벨 프린터는 쉬지 않고 돌아가는데, 매일 저녁 택배사의 실제 픽업 건수가 시스템의 출고 건수보다 300개 이상 모자랐다. 클레임, 환불, 재배송. 매일 수천 달러가 그냥 타들어갔다. 피킹은 정상이었다. 출력도 정상이었다. 사라진 주문들은 모두 WMS와 택배사 라벨 API 사이의 체인에서 죽어 있었다.
결론부터 말하겠다. 사라진 라벨이 프린터에서 죽는 경우는 거의 없다. 진짜 범인은 세 가지다. 요청이 우리 회사를 나가지 않았다. 타임아웃 재시도로 중복 라벨이 만들어졌다. 아니면 아무도 정합을 하지 않았다. 이 트러블슈팅 체인은 택배사 라벨 API 연동을 수년간 해온 경험에서 나온 것이다. 순서대로 따라가면 끊긴 지점이 보인다.
1단계: 요청이 우리 회사를 나갔는가?
주문을 잃는 가장 멍청한 방법은 WMS가 요청을 보내지 않는 것. 혹은 보내고 응답을 받지 못했는데, 통과된 것으로 착각하는 것이다.
내가 가장 먼저 보는 것은 항상 로컬 요청 로그다. WMS의 주문 상태가 아니라, 아웃바운드 게이트웨이의 호출 기록이다. 이 주문에 대해 "택배사 라벨 요청" 호출 기록이 있는가. 없으면 API 문서를 읽거나 타임아웃을 조정하는 것은 그만둬라. 문제는 우리 쪽에 있다. 단골 용의자들은 이렇다. 메시지 큐 컨슈머가 죽어 큐가 조용히 쌓이고 있다. 스케줄 잡이 시작조차 안 했다. 주문이 상태 전이에서 막혔다. OMS는 주문을 넘겼는데 WMS는 웨이브 릴리스를 기다리는 중이라 라벨 요청이 발화되지 않았다. 한두 번 본 게 아니다. 성수기의 혼란, 잘못 설정된 웨이브 정책, 그리고 수백 건의 주문이 "릴리스 대기"에 조용히 쌓여 있는데 라벨 요청은 한 번도 보내지지 않았다.
더 교활한 변형도 있다. 요청은 나갔는데 로그에 남지 않은 경우다. 성공만 기록하는 시스템도 있다. 로그 로테이션이 너무 공격적이라 정작 중요한 몇 분의 기록이 이미 사라진 경우도 있다. 고객사에 대한 나의 철칙은 이렇다. 라벨 API 호출은 전부 풀 로그로 남겨라. 무엇을 보냈고, 언제, 응답은 무엇이었고, 얼마나 걸렸는지. 택배사와 요금 불일치를 다투거나 고객 클레임을 처리할 때, 로그가 유일한 증거다. 로그가 불완전하면 끊긴 지점을 찾는 것을 아무도 도와줄 수 없다.
그래서 1단계의 결론은 단순하다. 로그에 기록이 없으면 문제는 우리 벽 안쪽에 있다. 내부 체인부터 고쳐라. 기록이 있으면 다음으로 넘어가라.
진짜 살인자는 타임아웃: 택배사 쪽에서 라벨이 이미 만들어졌을 수도 있다
주문을 잃는 가장 치명적이고 가장 억울한 방법이 이것이다.
상황은 이렇다. WMS가 택배사 라벨 API를 호출하는데, 택배사 처리가 너무 늦어 타임아웃을 초과한다(택배사마다 다르다. 각 사의 문서를 따를 것). WMS는 타임아웃으로 표시하고 자동으로 재시도한다. 두 번째 호출은 성공하고 라벨이 돌아오고 모두 환호한다. 그런데 첫 번째 요청이 사실 택배사 쪽에서 이미 라벨을 만들어 놓았다. 응답이 돌아오지 않았을 뿐이다. 이제 이 주문에는 라벨이 두 개, 추적번호가 두 개다.
두 가지 결과가 따른다. 첫째, 돈을 두 번 낸다. 라벨 생성 건당 과금하는 택배사도 있고, 보이드(무효화) 절차가 너무 고통스러워서 소규모 창고는 건별로 무효화하는 것을 아예 포기한다. 돈은 조용히 새어 나간다. 둘째, 창고는 한 장의 라벨만 소포에 붙여 출고한다. 나머지 한 장은 유령 라벨이 된다. 시스템에는 만들어졌고 고객은 추적할 수 있지만, 그 소포에 픽업 스캔이 찍히는 일은 영원히 없다. 고객센터가 조회해 본다. 유효한 추적번호, 추적 이벤트는 제로. 아무도 설명할 수 없다. 비용을 삼키고 재배송한다. 가장 화가 나는 것은 WMS는 정상으로 보이고 택배사 추적도 "정상"으로 보인다는 점이다. 양쪽 다 정상인데 화물은 움직이지 않았다.
해결책은 두 단어다. 멱등성(idempotency)과 재시도 정책.
멱등성이란 모든 라벨 요청에 업무상 고유 키를 싣는 것. 예를 들어 주문번호+패키지 순번. 같은 키로 반복 요청하면 택배사 API가 같은 라벨을 돌려준다. 연동 시 택배사와 확인할 것. 일부 API는 멱등성이 기본으로 켜져 있지 않다. 계약이나 설정에서 요청해야 한다. 이것 없이 재시도를 던지는 것은 스스로 지뢰를 묻는 일이다. 뭔가 터진 뒤가 아니라 협상 단계에서 계약서에 못 박아라.
재시도 정책이란 타임아웃 뒤에 무작정 재전송하지 않는 것이다. 내 방식은 이렇다. 첫 타임아웃에서는 먼저 택배사에 조회한다. 주문이나 패키지 참조번호로 라벨이 실제로 만들어졌는지 확인한다. 만들어졌으면 기존 것을 쓴다. 안 만들어졌을 때만 재전송한다. 한 번의 조회가 유령 라벨 산더미를 치우는 것보다 훨씬 싸다. 재시도 횟수에 상한을 두고, 간격을 두고, 택배사 시스템이 이미 버거워할 때 몰아붙이지 마라. 성수기에는 택배사 API 자체가 느리다. 무분별한 재시도는 더 느리게 만들 뿐인 악순환이다.

프린터는 어떤가. 프린터가 주문을 잃는 경우는 드물다. 출력은 됐는데 붙이지 않은 라벨, 다른 소포에 붙인 라벨. 그것은 현장 관리 문제로, 카메라와 피킹 기록으로 해결한다. API 문제가 아니다. API 체인에서 죽는 주문 중 열 번 중 아홉 번은 "타임아웃"이라는 단어에서 죽는다.
매일 정합을 돌리고 나머지는 전부 잡아내자
앞의 두 단계는 "뭔가 터졌을 때 어떻게 조사하는가"다. 이것은 "터졌을 때 어떻게 바로 알아차리는가"다.
체인이 아무리 탄탄해도 나는 고객사에 일일 정합 잡을 반드시 돌리게 한다. 로직은 세 줄이다. 택배사의 라벨 생성 건수를 가져오고(정합 API나 요금 다운로드로), WMS의 실제 출고 건수를 가져오고, 주문번호나 추적번호로 맞춘다. 차이가 사라진 주문이다. 정의에 주의하라. 보이드된 라벨은 제외하고, 택배사별로 따로 정합하라. A 택배사 라벨을 B 택배사에 세지 마라. 그리고 매일 정해진 시간에 돌려라. 나는 보통 이른 아침을 권한다. 택배사 정산 시간대를 피해서.
알람 임계값은 어떻게 정하는가. 내 경험칙은 이렇다. 차이가 그날 물량의 0.5%를 넘으면 알람, 2%를 넘으면 누군가의 전화기를 울려라. 차이가 날 때마다 알람하지 마라. 택배사는 야간 정산처럼 배치로 라벨을 만들기도 해서, 오늘 만든 라벨이 요금 파일에 내일 올라올 수 있다. 제로 톨러런스는 알람 무시 훈련일 뿐이다. 정작 중요할 때 아무도 보지 않게 된다. 임계값은 쓰라고 있는 것이지, 숭배하라고 있는 게 아니다. 너무 민감하게 잡으면 없는 것과 같다.
그 로스앤젤레스 3PL은 이 정합 잡 덕분에 살아남았다. 도입 전에는 하루에 몇 건이 사라지는지조차 말할 수 없었다. 그게 가장 무서운 부분이다. 문제의 크기를 모른다는 것. 가동 후 사라진 주문은 하루 300개 이상에서 한 자릿수로 줄었고, 나머지는 현장의 오부착뿐이었다. API와는 무관하다. 매일 아침 현장은 정합 리포트로 하루를 시작한다. 차이는 당일 조사한다. 문제는 밤을 넘기지 않는다.
이 체인을 기억하라. 먼저 로그, 다음에 타임아웃, 그리고 프린터. 정합은 매일이다.
영어판 번역본입니다. 내용이 다를 경우 영어판을 우선합니다.





