5일 연속 크론 4개가 죽었는데 알림은 0건이었습니다
매일 돌던 크론 4개가 5일 연속으로 실패했고, 실행 로그에는 17건이 남아 있었습니다. 그런데 그 사이에 제가 받은 알림은 0건이었습니다. 추정치가 아니라 로그 데이터를 직접 훑어서 나온 숫자이고, 크론 설정을 점검하다가 우연히 열어본 날에야 비로소 알게 됐습니다. 그날 열어보지 않았더라면, 이 침묵은 열흘은 더 이어졌을 가능성이 큽니다.

알림이 사라진 게 아니라, 실패를 세는 장치가 없었습니다
대상은 세컨드브레인 유지를 맡은 크론 4개였습니다. 하루의 세션을 증류하는 것, 인덱스 파이프라인을 지키는 워치독, 아침에 온몸을 정비하는 것, 밤에 지식을 승격시키는 것 — 매일 빠짐없이 도는 것들이었습니다. 10월 26일부터 네 개가 한꺼번에 쓰러졌고, 로그에 남은 오류는 전부 한 줄로 똑같았습니다. 모델 서버로 연결이 안 된다는 메시지였습니다. 밖에서 보기에 그 닷새는 전부 잘 돌아가고 있는 닷새와 모양이 똑같았습니다.
회수가 가장 많은 밤 승격은 5일 내내 실패했고, 나머지 셋은 각각 4건씩 남겼습니다. 합치면 정확히 17건입니다. 네 개가 같은 오류로 동시에 죽었다는 것 자체가 힌트였습니다. 병이 네 개 생긴 게 아니라, 공통의 물줄기 하나가 끊어진 거죠.
알림이 0건이었던 이유는 하나가 아니라 겹겹이었습니다. 첫째, 이 크론들은 서브 프로필에서 돌아서 결과가 기본적으로 로컬 안에만 남습니다. 그러니 죽어도 제 화면 밖에서는 조용히 죽는 거죠. 둘째, 실패를 세는 지표 자체가 없고 성공했을 때 나가는 알림만 있었습니다. 그래서 모든 게 죽어 있는 동안에는 소리 하나 나지 않았습니다.
세 번째 겹이 좀 부끄러운 부분입니다. 이걸 잡아줘야 할 파이프라인 워치독이, 정작 감시 대상과 같은 LLM을 보고 돌고 있었습니다. 감시자를 새로 쌓기 전에 이미 있던 감시자가 피감시자와 같은 배를 타고 있었다는 걸 발견한 셈입니다.
원인도 겹이 있었습니다
1차 원인은 리모트 서버의 LLM 엔드포인트였습니다. 기계는 멀쩡한데 엔드포인트만 죽어 있어서, 크론의 호출이 전부 연결 실패로 끝나던 상태였습니다. 이 정도면 서버가 죽었으니 폴백으로 넘기면 되지 싶습니다. 그런데 폴백이 돌지 않았습니다.
그 사정은 당일 오후에야 드러났습니다. 크론에 모델을 핀으로 고정해 두면, 폴백이 아예 켜지지 않는다고요. 핀은 쓸 모델을 못 박아두는 설정 항목인데, 이게 걸려 있으면 전환 로직 자체가 참조되지 않습니다. 넘겨줄 상대가 같은 계열이라 같이 죽어 있었을 문제보다, 아예 시도조차 안 된 문제가 먼저였습니다. 모델 고정 한 번으로 그 식당에만 배달을 묶어두는 셈이라, 그 식당 셔터가 내려가면 골목에 다른 식당이 아무리 많아도 그냥 굶게 됩니다. 5일간의 무알림 실패는 전부 이 조합이 만든 산물이었습니다. 엔드포인트가 죽은 것보다, 죽었을 때 넘어갈 다리를 못 놓아둔 게 진짜 원인이었습니다.
회의록도 조용히 죽어 있었습니다
로그를 훑다가 크론 말고 조용히 죽어 있던 걸 하나 더 찾았습니다. 룸 회의록 파이프라인인데요, 전사는 매번 성공하고 있었습니다. 그 다음 요약을 맡은 모델이 죽은 엔드포인트를 보고 있어서, 26일 이후 회의록이 0건이었습니다. 전사가 계속 돌아가니 문제 자체가 표면에 안 뜨는 구조였죠. 녹음은 쌓여가는데 결과물만 안 나오는 형태라, 모으는 사람 입장에서 더 낯설었습니다. 밀린 녹음 19건은 복구 후에 재처리 큐로 돌려서 회수했습니다. 소리 원본은 남아 있어서 그나마 회수할 게 있었던 셈이고, 이게 파일까지 함께 사라지는 종류였다면 되돌릴 방법 자체가 없었습니다.
고친 것 — 감시자는 LLM을 쓰지 않기로 했습니다
대응의 핵심은 피감시자에게 의존하지 않는 감시자를 새로 두는 것이었습니다. 신설한 센티넬은 15분 주기로 크론을 돌리되 LLM을 전혀 쓰지 않습니다. 모든 프로필의 실행 DB를 말없이 훑다가, 실패가 있을 때만 알림을 내보내고 아무 일 없으면 소리조차 내지 않습니다. 이전에는 알림이 없으면 그게 정상인 줄 알았는데, 이제는 알림이 없어야 비로소 정상입니다. DB 조회와 단단한 판정 한 줄로 돌아가는 단순한 루프라는 게 장점이라, 감시자 스스로가 또 다른 감시 대상이 될 여지가 작습니다. 실패할 때만 소리를 낸다는 한 가지 규칙 덕에, 이 알림은 스팸을 걱정 없이 켜둘 수 있습니다.
함께 LLM 서버 3종에 1토큰씩 실제 헬스프롭을 쏩니다. 두 번 연속 실패하면 다운으로 판정합니다. 회복되면 복귀 알림이 옵니다. 직접 재현해서 돌려본 테스트에서는 당일의 무알림 실패(인증 401)와, 일부러 죽여놓은 모델 2개를 전부 잡아냈습니다. 일부러 심어놓은 것까지 잡았으니, 일단은 돌아가는 셈이죠.
핀은 대량으로 풀었습니다. 브레인 크론 5개와 메일 크론 3개, 여기에 서빙 크론 하나에서 핀을 해제했더니, 죽은 쪽을 자동으로 피해 다른 서버로 넘어가는 폴백이 살아났습니다. 크론을 돌리는 봇 4개의 환경 파일에 게이트웨이 키도 채워 넣었습니다. 401의 직접 원인이 바로 그 키 누락이었습니다.
멈춘 게 아니라 정체된 것이었습니다
복구하니 무게가 상당했습니다. 밤 승격 크론이 5일치를 한꺼번에 돌리느라, 호출 한 번에 약 336초가 걸렸습니다. 컨텍스트 9만 토큰을 한 번에 삼키는 셈이니 밀린 처리 전체에 2시간이 들었습니다. 그 닷새는 멈춰 있었던 게 아니라 정체돼 있었던 겁니다. 막힌 데가 풀릴 때 아래로 밀려오는 물이 이 정도 무게라는 걸 보면서 실감했습니다.
안 남은 건 아니고, 남은 건 솔직히 적겠습니다. 여전히 꺼진 채로 남은 잡 23개를 정리 중이고, 로스터 문서가 죽은 서버 주소를 가리키던 것 같은 문서와 실제의 어긋남은 당일 일부만 고쳤습니다. 모델을 지정하지 않은 크론이 데스크톱의 최신 모델을 따라가서, 유료 모델로 돌고 있던 별건도 발견했습니다. 핀과 폴백의 기본값 설계는 다시 한 번 정리하기로 했습니다.
그래서 잣대 하나를 바꿨습니다. 자동화의 커버리지는 돌아가는 개수가 아니라, 실패를 세는 지표가 있느냐로 따져야 합니다. 알림이 성공인 쪽만 데려가는 방식으로 서 있으면 있어도 없는 것과 같다는 걸, 이번에도 톡톡히 배웠습니다. 여러분의 크론도 지금 조용히 죽어 있을지 모르니, 오늘 밤 자기 전에 실패 로그 한번만 열어보세요.