배경
작업을 백그라운드로 던지고 즉시 응답하게 바꾼 뒤, 호출 성공률이 아무것도 보증하지 않게 됐다. 그래서 "로그 파일이 N분 안에 갱신됐는가"로 감시를 걸었다.
함정 ① — 감시 대상이 조건부로 쓰이는 로그였다
처음 고른 것은 작업 로그였다. 그런데 그 로그는 처리할 것이 있을 때만 쓰인다. 신규 건이 0이면 아무것도 안 쓰고 끝난다. → 한가한 시간이 장애로 보고됐다.
★★★ "일이 있었다"를 기록하는 로그와 "돌았다"를 기록하는 로그는 다르다. 전자로 후자를 감시하면 작업이 완벽히 정상일 때 경보가 울린다.
★★ 그리고 오탐이 반복되면 사람이 경보를 끈다. 그 뒤에 오는 진짜 침묵은 아무도 안 본다 — 이 컬렉션의 반복 알림은 알림을 무의미하게 만든다와 같은 자리다.
→ ★ 하트비트는 작업 결과와 무관하게 진입 시점에 무조건 한 줄 쓴다. 감시는 그 줄을 본다.
함정 ② — ★★★ 그런데 하트비트는 침묵만 잡는다
무조건 쓰이는 로그라면 작업이 실패해도 쓰인다. ★★★ "돌았다"는 알지만 "성공했다"는 모른다. 백그라운드로 던진 작업이 조용히 죽는 경우는 여전히 안 잡힌다.
→ 층을 둘로 나눈다.
| 층 | 보는 것 | 잡는 것 |
|---|---|---|
| ① 하트비트 | 진입 로그의 갱신 시각 | 호출이 끊김 |
| ② 완료 기록 | 작업이 끝에 남기는 결과 | 작업이 실패·중단 |
★★ ②가 없으면 "정확히 10분마다 호출되고 아무 일도 일어나지 않는" 상태가 완벽한 정상으로 보인다.
★ 완료 기록에는 처리 건수를 같이 적어라. 다만 ⚠️ 0건이 계속되는 것을 곧바로 경보로 만들지는 마라 — 그것이 바로 함정 ①이다. 0이 정상인 시간대가 있다. 경보가 아니라 추세로 본다.
★★ 감시자는 감시 대상과 다른 자원에 있어야 한다
스케줄링을 외부 서비스로 옮기면 실패 방향이 침묵으로 바뀐다. 우리가 호출하는 구조는 실패가 에러로 오고, 외부가 우리를 호출하는 구조는 실패가 아무것도 오지 않음으로 온다.
★★★ 외부로 옮긴 자원은 감시도 함께 옮겨야 한다 — 외부에 맡긴 것을 외부가 감시하면 둘이 같이 죽는다. 내부에 최소한의 데드맨 스위치를 남겨라. ★ 이 컬렉션의 비상 수단이 정상 자원을 쓰면 비상시에 못 쓴다와 같은 원리다.