로컬 AI 회사가 멈췄을 때 먼저 확인한 것들
24시간 돌아가는 로컬 AI 회사가 멈춘 것처럼 보일 때, 저는 모델 한도보다 먼저 스케줄러, 실행 모드, 로그, 실제 컨테이너 상태를 확인해요. 오늘 점검한 순서를 기록해 둡니다.
오늘은 로컬 AI 회사가 멈춘 것처럼 보였어요. Claude 사용량이 막히면서 블로그 초안 생성, 마케팅 루프, work-cell 실행이 다 같이 멈춘 느낌이었거든요.
이럴 때 바로 "모델이 문제다"라고 단정하면 놓치는 게 생겨요. 저는 먼저 세 가지를 나눠 봅니다.
- 스케줄러는 살아 있는가
- 실행 대상은 올바른 모드인가
- 실제 서비스는 healthy인가
n8n은 실제로 살아 있었어요
먼저 n8n 컨테이너 상태를 봤어요. 결과는 n8n 컨테이너가 Up이고 healthy였어요. cloudflared와 ngrok도 떠 있었고요. 즉, n8n 자체가 죽어서 전체가 멈춘 건 아니었습니다.
이 확인이 중요해요. 자동화가 안 된다고 느낄 때 원인은 하나가 아니거든요. n8n이 죽었을 수도 있고, launchd가 스크립트를 못 찾았을 수도 있고, 모델 provider가 실패했을 수도 있어요. 증상을 하나로 묶으면 고치는 방향도 흐려집니다.
문제는 실행 모드였어요
work-cell은 스크립트 안에서 환경 파일을 읽고 실행 모드를 정합니다. 이번에는 실제 활성 설정이 AGENT_MODE=claude로 고정돼 있었어요. 코드에 Codex fallback을 붙여도, launchd가 계속 Claude 전용 모드로 실행하면 fallback은 타지 않아요.
그래서 실행 모드를 auto로 바꿨어요.
claude: Claude만 시도codex: Codex만 시도auto: Claude 먼저, 실패하면 Codexstub: 테스트용
이런 작은 설정 하나가 운영에서는 큽니다. 코드는 맞는데 설정이 옛날 상태면, 실제 런타임은 전혀 다르게 움직여요.
로그보다 실제 경로를 봐야 해요
launchd는 터미널과 환경이 달라요. 터미널에서는 잘 되던 명령도 launchd에서는 PATH가 달라서 실패할 수 있어요. 예전에 Claude 실행 파일 경로 때문에 rc=127이 나온 적도 있었어요.
그래서 저는 반복 작업을 볼 때 항상 이 순서로 봅니다.
- plist가 어떤 스크립트를 실행하는지
- 스크립트가 어떤 env 파일을 읽는지
- env 파일에 실제 모드가 무엇인지
- 로그가 어디에 쌓이는지
- 마지막으로 실제 결과물이 생겼는지
대시보드나 로그는 힌트예요. 실제 실행 경로와 결과물이 더 중요합니다.
fail-closed가 있어야 마음이 편해요
이번에 blog draft 쪽도 같이 고쳤어요. 예전에는 모델 호출이 실패해도 경우에 따라 noop처럼 보일 수 있었어요. 그러면 "오늘은 쓸 게 없었나 보다" 하고 지나가게 됩니다. 실제로는 provider가 실패했는데요.
지금은 LLM provider가 실패하면 model_unavailable로 남기고 알림을 보내게 했어요. 자동화에서는 실패를 조용히 숨기는 것보다 시끄럽게 멈추는 편이 낫습니다.
특히 발행 자동화는 더 조심해야 해요. 글이 만들어지지 않았는데 만들어진 것처럼 보이거나, 검증이 안 됐는데 발행되는 게 가장 위험하니까요.
오늘의 운영 메모
오늘 점검하면서 다시 확인한 원칙은 이거예요.
- 컨테이너 상태와 스케줄러 상태를 분리해서 본다
- 코드 변경만 믿지 말고 실제 env를 확인한다
- 모델 실패는
noop이 아니라 별도 상태로 기록한다 - fallback은 켜되, 같은 모델 자기 검토는 자동 완료하지 않는다
- 공개 발행은 사람이 마지막에 확인한다
혼자 운영하는 로컬 AI 회사는 멋진 말보다 이런 작은 경계로 유지되는 것 같아요. 24시간 돌리는 일은 "계속 실행"보다 "어디서 멈춰야 하는지"를 정하는 일에 가깝습니다.
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.