De-Fi 프로토콜 데이터를 수집하는 CollectJob 중 하나가 오랫동안 0건이었다. 그쪽에 데이터가 없는 것으로 보고 넘어갔다.
Table of contents
Open Table of contents
증상 — 0건으로 남던 로그
한참 뒤에 응답을 찍어 보니 401 로 인증이 실패하고 있었다. 우리 코드는 RestTemplate 응답 본문을 목록으로 파싱하려 했고 파싱 결과가 비어서 0건으로 처리했다.
HttpStatus 를 보지 않으니 실패가 성공한 0건처럼 기록됐다. collected=0 이라는 줄이 매일 로그에 남고 있었다.
원인 — 정상 0과 실패 0
프로토콜 쪽 활동이 없는 날에는 실제로 0건인 경우가 있다. 그러면 같은 로그가 정상과 실패 두 가지를 뜻하게 된다.
구분이 안 되는 신호는 며칠이 지나도 아무도 이상하게 여기지 않는다. 몇 달이 지나도록 그 상태가 유지된 이유가 거기 있었다.
조치 — 상태 코드와 본문 결과 코드
가장 기본적인 것부터 고쳐서 HttpStatus 가 2xx 가 아니면 예외를 던지게 했다. RFC 7235 대로 401 은 유효한 자격 증명이 없어 요청이 적용되지 않았다는 뜻이므로 0건과 같은 줄에 설 수 없다.
다만 상태는 200 인데 본문에 {"code": "AUTH_EXPIRED"} 가 담겨 오는 프로토콜도 있었다. 그래서 본문의 결과 코드도 확인하게 했고 형식이 프로토콜마다 달라 연동별로 따로 짜야 했다.
판단 기준 — 성공한 지 오래된 것을 알린다
더 근본적인 것은 마지막으로 실제 데이터를 받은 시각 last_success_at 을 MongoDB 의 collect_runs 에 남기는 일이었다. last_run_at 과 나란히 두면 매일 돌지만 몇 달째 성공이 없다는 것이 바로 보인다.
두 가지 방법이 있었다. 실패했을 때 알리는 것과, 성공한 지 오래됐을 때 알리는 것이다. 뒤쪽을 골랐다. 이유는 조용한 실패는 실패 신호를 안 내므로 성공의 부재로만 잡히기 때문이다. 대신 프로토콜 활동이 정말 없는 날에도 알림이 오는 것을 감수했다.
만료와 대체 경로
원인이 API 키 만료였으므로 api_credentials 에 연동별 issued_at 과 expires_at 을 기록하고 미리 알리게 했다. 만료는 예측 가능한 실패라서 미리 막을 수 있는 종류다.
다른 연동도 훑어보니 비슷한 상태가 몇 개 있었는데 심각도는 달랐다. 같은 데이터를 다른 프로토콜 API 로도 받고 있으면 실질 유실이 적고 그 연동이 유일하면 유실이 그대로 쌓이므로 우선순위를 그것으로 갈랐다.
정리
- 수집 0건이 정상일 수도
401인증 실패일 수도 있다 - 구분이 안 되는 신호는 오래 지나도 아무도 안 본다
HttpStatus를 먼저 확인하고 실패를 0건으로 넘기지 않는다- 오류를
200응답 안에 담는 시스템이 있으므로 본문도 본다 last_success_at을 기록해last_run_at과 나란히 둔다- 실패 알림이 아니라 성공 부재 알림으로 조용한 실패를 잡는다
- API 키 만료는 예측 가능하므로
expires_at으로 미리 알린다 - 같은 증상도 대체 경로 유무에 따라 심각도가 다르다