마켓에서 이미 검색되지 않는 상품 약 2만 건을 재등록해야 해서 먼저 현재 상태를 조회했다. 처음에는 갱신 작업이 실패해 쌓인 것으로 봤는데 마켓에 없으니 갱신이 안 될 것이라고 생각했기 때문이다.
Table of contents
Open Table of contents
유형이 다른 작업
작업 이력을 보니 갱신이 아니라 연동 해제 작업이었다. 그 작업은 이미 생성되고 completed_at까지 찍혀 있는데 executed_at이 비어 있고 deleted_at도 없었다.
연동 쪽도 함께 보니 approval_type이 특정 값이고 status는 갱신 성공이며 channel_product_no가 살아 있었다. 마켓에서는 사라졌는데 우리 쪽에는 번호가 남아 있는 상태다.
원인 — 두 단계 중 하나
코드를 보니 연동 해제가 두 단계였다. 첫 단계 unlinkStep1()에서 해제 작업을 만들고 completed_at과 함께 approval_type을 바꾸며 두 번째 단계 unlinkStep2()에서 실제 삭제 처리와 번호 정리를 한다.
두 번째가 안 돌아 있었다. 자동 경로로 연동이 끊긴 건들이 첫 단계까지만 가고 멈춰 있던 것이다. 각 컬럼은 의미가 약한데 조합하면 어느 단계까지 갔는지가 정해진다.
판단 기준 — 지문과 이름
이 상태를 알아보는 조합을 지문으로 정리했다. 작업 쪽은 job_type이 해제이고 completed_at이 있고 executed_at과 deleted_at이 비어 있는 것이며 연동 쪽은 approval_type이 그 값이고 status가 갱신 성공이며 channel_product_no가 있는 것이다.
특히 approval_type 값 하나가 그 자체로 단계를 뜻하고 있었다. 이 조합에 1단계 완료 2단계 대기라는 이름을 붙여 두니 다음에 같은 것을 빨리 알아볼 수 있게 됐다.
주의 — 오진했을 때의 루프
지문을 알고 나니 두 가지 방법이 있었는데 중지 작업을 새로 만들고 연동 레코드를 SQL로 손보는 것과 기존 unlinkStep2()를 그대로 부르는 것이다. 뒤쪽을 골랐다. 이유는 그 함수가 삭제 처리와 번호 정리를 이미 한 묶음으로 하고 있어서다. 대신 한 건씩 부르는 느린 실행을 감수했다.
모르고 연동 정상으로 판단했으면 어떻게 되는지도 따라가 봤다. channel_product_no가 있으니 연동됐다고 보고 갱신 작업을 만들 텐데 마켓에 그 번호가 없으니 실패하고 재시도하며 계속 반복된다. 갱신 작업만 무한히 재생성되고 실패하는 루프가 되며 실제로 그렇게 쌓인 것이 있었을 수 있다.
조치 — 필수 게이트
대량 복구 대상을 고를 때 이 지문을 조건으로 넣었다. approval_type이 그 값이고 channel_product_no가 있는 것만 대상으로 삼는다.
이 게이트를 안 넣으면 정상 연동된 것까지 unlinkStep2()를 부르게 되고 그것은 멀쩡한 연동을 끊는 일이다. 복구 스크립트에서 대상 조건은 안전장치이지 편의가 아니다.
교훈 — 유형부터 확인하는 순서
이 조사가 오진에서 시작했다는 것이 남길 만하다. 갱신 작업이 실패했다는 전제로 조사를 시작했고 그 방향으로 계속 갔다.
방향이 바뀐 계기는 job_type 컬럼을 확인한 것이었다. 작업이 안 되고 있다는 증상은 같아도 어떤 작업이 안 되는지가 다르면 완전히 다른 얘기가 된다. 증상이 비슷하면 유형부터 확인하는 것이 조사 순서의 첫 줄이 됐다.
정리
- 여러 상태 컬럼의 조합이 어느 단계까지 갔는지를 말한다
- 다단계 처리가 중간에서 멈춘 상태로 장기 잔존할 수 있다
- 그 상태의 지문을 정리하고 이름을 붙인다
- 모르고 정상으로 판단하면 다른 작업만 계속 재생성되고 실패한다
- 복구는 새로 만드는 것이 아니라 다음 단계를 부르는 것일 수 있다
- 대량 작업에는 그 지문을 필수 게이트로 넣는다
- 게이트를 안 넣으면 멀쩡한 것을 건드린다
- 증상이 비슷하면
job_type부터 확인한다