처리가 열흘 넘게 멈춰 있는 출금 건을 조사하다가 withdrawals 레코드를 열었다. 노드 전송과 연결되는 txid 와 broadcast_at 이 비어 있어서 그것이 원인으로 보였다.
Table of contents
Open Table of contents
증상 — 눈에 띈 빈 값들
값이 들어 있는 컬럼은 그냥 지나가고 NULL 인 것에 시선이 갔다. 이름도 노드 전송과 연결되는 값 같아서 없으면 문제로 읽혔다.
그 상태에서 값을 채우는 UPDATE 를 돌리고 싶어진다. 두 가지 방법이 있었다. 바로 노드에서 txid 를 찾아 채우는 것과, 그 전에 이 값이 정말 이상한지를 정상 건과 대조해 확인하는 것이다. 뒤쪽을 골랐다. 이유는 운영 데이터의 UPDATE 는 되돌리기 어려워서다. 대신 회원이 하루 더 기다리는 것을 감수했다.
검증 — 정상 건도 같은 값이었다
같은 코인의 정상 완료된 건을 조회하니 그 컬럼들이 똑같이 비어 있었다. 이 건은 transfer_type = 'INTERNAL' 인 회원 간 내부 이체라 노드 전송 자체가 없고, txid 가 비어 있는 것이 이 유형의 정상 패턴이었다.
비어 있다는 것이 이상한지는 그 컬럼의 정상 상태를 알아야 판단되는데 그것을 모르면 눈에 띈다는 이유만으로 원인이 된다. 확인 없이 UPDATE 를 돌렸으면 아무 관계없는 값을 넣어 운영 데이터를 오염시켰을 것이다.
원인 — 진짜 차이가 있던 자리
두 건을 나란히 놓고 전 컬럼을 비교하니 승인 정보에 해당하는 approved_by·approved_at·otp_verified_at·risk_checked_at 네 항목이 멈춘 건에서만 비어 있었다. 눈에 띄던 컬럼이 아니라 그쪽이 갈린 자리였다.
그러면 이 건은 노드 연결이 안 된 것이 아니라 승인 단계가 안 진행된 것이다. 조치도 값을 채우는 것이 아니라 위험 심사를 마치고 승인을 진행시키는 것이었다.
이름이 그럴듯한 컬럼
처음에 잘못 본 이유 하나가 컬럼 이름이었다. txid 처럼 이름이 그 값의 용도를 그럴듯하게 설명하면 비어 있는 것이 결함으로 읽힌다.
실제로 내부 이체는 장부만 옮겨서 그 컬럼을 쓰지 않았다. 이름이 그럴듯할수록 그 유형이 실제로 쓰는지를 먼저 확인해야 했다.
판단 기준 — 조치 전에 묻는 네 가지
운영 데이터를 고치기 전에 정상 건도 그 값인지와 무엇으로 채울 것인지와 채우면 무엇이 달라지는지와 되돌릴 수 있는지를 확인하게 됐다. 둘째가 특히 중요한데 비어 있으니 무언가 넣어야 한다는 것은 근거가 아니다.
대조군은 같은 코인과 같은 transfer_type 과 비슷한 시기로 조건을 맞춰야 비교가 된다. 정상 건도 하나만 보면 그것이 특수한 경우일 수 있어서 LIMIT 20 으로 여러 건을 봤다.
정리
- 비어 있는 값이 눈에 띄지만 이상한지는 정상 상태를 알아야 안다
- 고치기 전에 같은 조건의 정상 건과 대조한다
- 정상 건을 여러 개 봐야 특수한 경우에 안 속는다
- 눈에 띄는 컬럼만 보지 말고 전 컬럼을 비교한다
- 진짜 차이는
approved_at처럼 눈에 안 띄던 자리에 있을 수 있다 txid처럼 이름이 그럴듯한 컬럼일수록 실제로 쓰는지 확인한다- 비어 있으니 채워야 한다는 것은 근거가 아니다
- 조치 전에 정상 여부와 근거와 효과와 되돌림을 묻는다