
지방의 수산물 도매업체가 멈춰버린 AI 에이전트를 자동으로 감시하고 복구하는 시스템을 도입한 기록
요약
수산물 도매업체에서 Claude Code 에이전트의 중단 현상을 해결하기 위해 도입한 자동 감시 및 복구 시스템(Watchdog)에 관한 기록입니다. 프로세스 생존 여부가 아닌 로그 파일의 수정 시각을 기준으로 에이전트의 상태를 판단하여, 기계가 해결할 수 있는 문제와 사람의 개입이 필요한 문제를 구분하여 대응합니다.
핵심 포인트
- 에이전트의 정지 유형을 Silent Hang과 명시적 서버 에러로 구분하여 대응 전략 수립
- PID 대신 로그 파일의 최종 수정 시각(mtime)을 활용해 상태 감시의 정확도 향상
- 기계가 자동 복구할 영역과 사람에게 넘길 영역을 명확히 구분하여 운영 효율화
먼저 실례를 하나 들겠습니다. 저희 AI 팀은 여러 대의 PC에서 작동하고 있는데, 그중 한 대의 에이전트가 어젯밤 서버 측 에러로 인해 정지했습니다. 사람이 알아차리고 수동으로 다시 실행하기까지 약 5시간이 걸렸지만, 정지 사실의 감지는 자동으로, 복구 후 정상화 판정도 자동으로 이루어졌습니다. 이 기사는 "AI 에이전트가 멈추는 현상"을 운영 측면에서 어떻게 다룰 것인가에 대해, 실제 기기의 로그를 바탕으로 작성한 기록입니다. 화려한 완전 자동화 이야기가 아니라, 어디까지를 기계에 맡기고 어디서부터 사람에게 넘길 것인가에 대한 경계선을 긋는 방법에 관한 이야기입니다.
왜 수산물 도매업체가 에이전트의 "사활 감시"를 만드는가
저희는 오이타현의 수산물 도매업체입니다. 사내에서는 여러 대의 PC에서 Claude Code 에이전트가 상시 가동되고 있으며, SNS 포스팅, FAX 전표의 OCR, 영상 제작, 경리 처리 등을 분담하고 있습니다. "상시 작동한다"는 점이 이번 이야기의 핵심입니다.
인간 오퍼레이터라면 툴이 멈췄을 때 알아차리고 재시작할 것입니다. 하지만 야간을 포함하여 계속 움직이는 에이전트가 멈췄을 때, 누가 알아차릴 것인가. 알아차리지 못하면 해당 담당자가 맡았던 업무(전표 OCR이나 포스팅)는 조용히 멈춥니다. 에러도 내지 않고 그저 멈추는 것. 이것이 가장 무섭습니다.
그래서 각 에이전트가 "살아있는가"를 별도의 프로세스로 감시하여, 멈추면 자동으로 툭 건드려보고(nudge), 안 되면 사람을 부르는—— way 식의 사활 감시 (watchdog)를 도입했습니다. 이 기사는 그 실제 기기 기록입니다.
에이전트가 "멈추는 것"에는 두 가지 종류가 있다
운영해 보니 알게 된 것은, 멈추는 방식에는 성질이 다른 두 가지 종류가 있으며, 올바른 대처법이 정반대라는 점입니다.
(A) 사이런트 행 (Silent Hang, 무언의 정지)
프로세스는 살아있지만 응답이 돌아오지 않는 상태. 네트워크의 일시적인 정체 등이 원인입니다. 이는 세션을 재시작하면 해결되는 경우가 많습니다.
(B) 명시적인 서버 에러
API Error: Stream idle timeout
과 같이, 서버 측에서 명확하게 에러를 반환하며 멈추는 상태. 이는 재시작해도 무의미한 경우가 많습니다. 동일한 서버 조건에 다시 부딪힐 뿐이기 때문입니다.
이 구분이 설계의 중심이 되었습니다. (A)는 기계가 재시작하여 해결한다. (B)는 기계가 재시작해도 해결되지 않으므로, 헛수고하지 않고 사람에게 넘긴다. 같은 "멈춤"이라도 기계가 노력할 영역과 사람에게 넘길 영역을 나눈 것입니다.
메커니즘: "마지막으로 움직인 시각"만을 본다
사활 감시에서 고민되는 점은 "무엇을 살아있다고 간주할 것인가"입니다. 프로세스 ID (PID)의 생사만으로는 사이런트 행 (프로세스는 살아있으나 무언의 상태)을 놓치게 됩니다.
저희가 채택한 방식은 에이전트의 작업 로그 (transcript) 파일의 최종 수정 시각 (mtime)이 진행되고 있는가를 보는 방식입니다.
- 에이전트가 어떤 일을 하면 반드시 로그 파일에 기록이 남음 $\rightarrow$ mtime이 전진함
- 일정 시간 mtime이 멈춰 있으면 "멈춰 있음"으로 판정
- mtime이 다시 전진하면 "복구됨"으로 판정
이 방식의 장점은 PID에 의존하지 않는다는 것입니다. 사람이 수동으로 재시작하면 프로세스 ID는 바뀌지만, 로그 파일은 다시 연결되어 동일한 파일에 기록이 계속되기 때문에, 새로운 프로세스라도 "복구"를 자동으로 감지할 수 있습니다. 수동으로 고쳐도 watchdog이 제대로 "고쳐졌다"고 기록해 줍니다. 이는 후술할 사고에서 실제로 효과를 발휘했습니다.
복구 단계: 툭 건드리기 $\rightarrow$ 재건 또는 사람 부르기
멈춤을 감지했을 때 곧바로 재시작하지는 않습니다. 단계를 밟습니다.
- NUDGE (툭 건드리기) $\times$ 3: 먼저 가볍게 건드려 봅니다 (입력을 보내 반응을 유도함). 일시적인 정체라면 이것으로 돌아옵니다. 실제로 어젯밤 사고에서도 첫 번째 재발 전에는 건드리기 한 번으로 자동 복구되었습니다.
- 판정: 3번 건드려도 돌아오지 않을 때, (A) 사이런트 행이라면 자동으로 재시작, (B) 명시적인 서버 에러라면 재시작하지 않고 에스컬레이션 (사람을 부름).
- ESCALATE (사람을 부름): 담당자에게 메일로 통지. "이것은 사람의 손길이 필요함"을 명확히 전달.
포인트는 기계가 "스스로는 고칠 수 없다"고 판단하여 솔직하게 사람에게 넘기는 것입니다. 무엇이든 자동으로 리트라이(retry)하게 만들면, 고쳐지지 않는 것을 끊임없이 두드리기만 하여 사태를 파악할 수 없게 됩니다. 고칠 수 없는 것은 빠르게 사람에게 올리는 편이 결과적으로 더 빠릅니다.
어젯밤의 실제 기기 기록 (사고의 전말)
마침 이 기사를 쓰기 전날 밤, (B)의 서버 에러가 발생했기에 그 전말을 올립니다.
- 20:44 에이전트 한 대가
Stream idle timeout
로 정지. watchdog이 이를 감지하고 툭 쳐서(nudge) 1회 시도 → 20:47 자동 복구 (mtime 전진을 감지) -
20:51 동일한 에러 재발. 툭 치는 시도를 3회(약 4분 간격) 수행했으나 복구되지 않음 -
20:59 명시적인 서버 에러로 판단 → 재시작은 무효하므로 스킵하고, 에스컬레이션 (담당자에게 메일 알림) -
~익일 02:05 서버 측 원인이므로 자동 복구가 불가능하여 대기 (약 5시간). 담당자가 아침에 인지하고 수동 터미널에서 Enter를 1회 입력하여 세션 재개 -
02:05 watchdog이 로그의 전진을 감지하여, 자동으로 '복구'를 클로즈(close)
5시간 동안 멈춰 있었던 것은 사실입니다. 하지만 이것은 설계대로의 동작이었습니다. 서버 측 에러는 기계가 재시작해도 고쳐지지 않으므로, watchdog은 무의미한 시도를 하지 않고 사람을 기다립니다. 그리고 사람이 고친 순간, 기계가 자동으로 정상화를 확인합니다. '기계가 할 수 있는 일'과 '사람만이 할 수 있는 일'이 깔끔하게 나뉘어 돌아갔다는 기록입니다. (※ 이 5시간의 대기 시간을 더 줄이기 위해, 사이런트 행(silent hang) 유형의 자동 재시작을 운영 환경에서 활성화하는 작업을 별도로 진행 중입니다.)
빠졌던 지점: "멈춘 것처럼 보이지만" 멈추지 않았다
구현 과정에서 가장 가슴 철렁했던 것은, 감시 로그 자체가 순간적으로 "동결"된 것처럼 보였다는 점입니다.
다른 머신에서 감시 상태를 읽으러 갔을 때, 최종 업데이트 시각이 멈춰 있는 것처럼 보였습니다. "watchdog이 죽었나?" 하고 순간 당황했지만, 원인은 단순했습니다. 우리가 읽으러 간 시점이 마침 상대방의 쓰기 직전이었을 뿐이었습니다. 읽기 타이밍의 오차(read-timing artifact)였을 뿐, 실체는 움직이고 있었습니다.
교훈은, "한 번 읽었을 때 멈춰 보였다"를 고장의 증거로 삼지 않는 것입니다. 약간의 시간을 두고 다시 읽어 전진 여부로 판정해야 합니다. 사활 감시(heartbeat monitoring)를 만드는 쪽에서는 자신의 관측을 의심하는 습관을 가질 필요가 있었습니다.
설계 판단: 감시 역할은 별도의 머신에 둔다
또 다른 판단은, 감시 역할을 피감시 대상과 동일한 머신에 두지 않는 것입니다. 머신 자체가 다운되면 그 머신 위의 감시 역할도 함께 사라집니다. 따라서 각 머신의 생사는 별도의 물리 머신에서 독립적으로 확인할 수 있도록 했습니다. 중요한 복구 판정은 두 개의 독립된 경로를 대조하여 비로소 "확정"하도록 했습니다.
이는 생선의 검수와 같은 발상입니다. 스스로 "괜찮습니다"라고 말하는 사람의 자기 신고만으로는 검수가 되지 않습니다. 다른 눈으로, 다른 각도에서 확인해야 합니다.
결과
- 에이전트가 굳었을 때,
사람이 보고 있지 않아도 감지되어 담당자에게 메일이 발송되게 됨 - (A)사이런트 행은 기계가 자동으로 재건하고, (B)서버 에러는 무의미한 시도 없이 사람에게 넘긴다는 구분선을 실제 사고를 통해 검증함 - 수동으로 고친 케이스에서도, watchdog이
자동으로 정상화를 확인하고 클로즈함 (PID에 의존하지 않는 mtime 감시가 효과를 발휘함)
마치며 — "멈추지 않는 것"보다 "멈췄음을 아는 것"
완전히 멈추지 않는 시스템은 만들 수 없습니다. 클라우드 서버 측에서 발생하는 일은 우리가 막을 수 없습니다. 그래서 목표를 "멈추지 않는 것"이 아니라, **"멈췄음을 반드시 알 수 있을 것", "기계와 사람의 담당 범위가 명확할 것"**에 두었습니다.
AI 에이전트를 업무에 상주시키면 반드시 이 문제에 부딪힙니다. 굳어버린 것을 아무도 알아차리지 못하는 사고가 가장 무섭습니다. 사활 감시는 소박해 보이지만, 에이전트를 "한번 돌려보는 단계"에서 "업무에서 계속 사용하는 단계"로 넘어가기 위한 필수적인 발판이라고 생각합니다.
참고로 이 글도 사내 장애 대응 기록(복구 장부)에서 거의 그대로 가져온 것입니다. 사내 운영 로그와 발신 소재의 일석이조 활용. 쓰는 작업을 늘리지 않고 발신한다는 것 또한 저희의 방침입니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기