AI 에이전트를 위한 충돌 점검 도구를 만들었고, 이를 통해 실제 운영 환경의 붕괴를 분석했습니다 — 이후 업스트림 PR이 진단이 옳았음을
요약
AI 에이전트의 안정성을 점검하는 도구인 ARK를 통해 실제 운영 환경에서 발생한 시스템 붕괴 원인을 분석한 사례입니다. 메모리 누수를 유발하는 무제한 반복 작업과 세션 재설정 시 발생하는 상태 불일치 문제를 해결하는 방법을 다룹니다.
핵심 포인트
- 캐시되지 않은 전체 스캔이 메모리 급증 및 OOM을 유발할 수 있음
- TTL 캐시와 호출 병합(coalescing)을 통해 무제한 반복 작업 방지 가능
- 세션 재설정 시 동일한 ID 반환으로 인한 멱등성 경계 버그 주의
- 에이전트 시스템의 상태 불일치(state mismatch) 진단 중요성
I built a crash-checkup tool for AI agents, then used it to dissect a real production meltdown — and upstream PRs later proved the diagnosis right
저는 제 개인적인 용도로 사용할 작은 도구들을 만드는 인디 개발자입니다.
얼마 전 저는 ARK — Agent Reliability Kit라고 불리는 것을 만들었습니다. 이것은 한 가지 좁은 기능만을 수행합니다. 새벽 3시에 에이전트를 죽게 만들 가능성이 가장 높은 세 가지 실패 유형(failure classes)에 대해 에이전트 시스템의 상태를 점검(health-checks)하는 것입니다. 제가 이것을 만든 이유는 바로 그 유형들이 저를 괴롭혔기 때문입니다.
그러던 어느 날, OpenClaw 이슈 트래커를 살펴보던 중 #113434 이슈를 발견했습니다.
Windows 11의 한 개발자가 2026.7.2-beta.4로 업그레이드한 후, Gateway의 메모리가 사용 가능한 모든 RAM을 다 써버릴 때까지 계속 상승하다가 충돌(crash)하는 것을 목격했습니다. 더 이상한 점은, Builder/Codex 세션이 다음과 같은 메시지를 내보내며 계속 거부되었다는 것입니다:
Codex session generation is no longer current: <session-id>
세션을 재설정(Resetting)해도 도움이 되지 않았습니다.
저의 첫 반응은 여러분과 같았습니다. "또 다른 메모리 누수(memory leak)네, 스왑(swap)을 제안하고 넘어가자." 하지만 그 no longer current라는 문구가 저를 멈추게 했습니다. 그것은 메모리 문제처럼 느껴지지 않았습니다. 핸드셰이크(handshake)/상태 불일치(state mismatch)처럼 느껴졌습니다. 그래서 계속 읽어 내려갔고, 읽으면 읽을수록 상황은 더 명확해졌습니다. 이것은 단 하나의 버그가 아니었습니다. 그것은 **동일한 사고에서 충돌한 두 개의 독립적인 회귀(regressions)**였습니다.
함정 #1: RAM을 끓게 만드는 캐시되지 않은 스캔 (uncached scans)
모든 Control-UI 틱(tick)마다 sessions.catalog.list와 sessions.files.list를 새로 호출했습니다. 이는 각각 Codex 세션 저장소에 대한 **전체 스캔(full scan)**이었습니다. 저장소가 크면 → 스캔이 느려지고 → 이전 스캔이 끝나기 전에 다음 틱이 새로운 스캔을 시작하며 → 스캔이 중첩되고 → Gateway 전체의 응답 불능 및 OOM(Out of Memory)이 발생할 때까지 메모리가 단조 증가(monotonically climb)하게 됩니다.
이러한 유형을 **무제한 반복 작업(unbounded repeated work)**이라고 부릅니다. 해결 방법은 다음과 같습니다: 짧은 TTL(Time-To-Live) 캐시를 추가하고, 동시에 호출하는 호출자들을 하나의 진행 중인 약속(in-flight promise)으로 병합(coalescing)하는 것입니다. 두 가지 사고방식만 적용하면 메모리 곡선은 계단식에서 평탄한 직선으로 변합니다.
함정 #2: 재설정(reset) 시 생성물은 은퇴하지만 이전 ID를 반환함
이것이 no longer current의 진짜 원인이었습니다.
sessions.reset은 현재의 Codex _generation (생성물)_을 무효화하지만, 클라이언트에게는 **동일한 세션 ID (session ID)**를 반환합니다. 다음 턴에 클라이언트가 해당 ID에 결합된 이전의 generation token (생성 토큰)을 제시하면, 서버는 이를 거부합니다. 즉, 당신의 generation (생성물)은 은퇴한 것입니다.
전형적인 **멱등성 경계 버그 (idempotency-boundary bug)**입니다. 변이 (mutation)가 부작용 (side effect, generation bump)을 일으켰지만, 호출자의 핸들 (handle)은 이를 전혀 알지 못했습니다. 수정 방향: reset은 기존 ID를 조용히 재사용하는 대신, 명시적인 재결합 (rebind)을 위해 새로운 generation binding (생성물 결합)을 반환해야 합니다.
함정 #3: 백프레셔 (backpressure) 없는 UI 폴링 (polling)
탭이 많아질수록 → 폴링이 배가되고 → 함정 #1이 증폭됩니다. 디바운스 (Debounce)를 2초 이상으로 설정하고, 숨겨진 상태일 때는 일시 중지하세요.
진짜 발견은 이들을 나열한 후에 찾아왔습니다
두 개의 치명적인 발견과 한 개의 중간 수준 발견 — 그리고 이들은 ARK가 방어하는 세 가지 실패 클래스 (failure classes)와 일대일로 매칭되었습니다:
| 발견 사항 | 실패 클래스 | ARK 방어 기제 |
|---|---|---|
| F-1 캐시되지 않은 스캔 (uncached scans) | 경계 없는 반복 작업 (Unbounded repeated work) | IdempotencyGuard |
| ... |
제가 똑똑해서가 아니라, 이러한 실패 모드 (failure modes)가 에이전트 시스템에서 그만큼 흔하기 때문입니다.
그래서 단순히 "캐시를 추가해 보세요"라는 댓글을 남기는 대신 (너무 가벼운 대응이며, 그 밤을 견뎌낸 사람에 대한 예의가 아닙니다), 근본 원인 테이블, 코드가 포함된 수정 방안, 그리고 오늘 바로 실행할 수 있는 임시 조치 체크리스트를 포함한 구조화된 진단 보고서로 전체 분석 내용을 작성했습니다. 정적 페이지이며, 가입도 트래킹도 없습니다:
📋 https://ark-6ek.pages.dev/reports/openclaw-113434
에필로그: 이야기는 제삼자에 의해 마무리되었습니다
제가 게시한 다음 날, 한 사용자가 해당 이슈(issue) 아래에 최신 메인(current-main) 업데이트를 게시했습니다. 의견이 아닌, **머지된 PR (merged PRs)**들이었습니다:
- #114056: reset이 이전 ID를 재사용하는 경로를 수정함 (함정 #2)
- #114401 / #114478: 전체 재스캔을 점진적 폴딩 (incremental folding) + 제한된 LRU + singleflight + 페이징 yield (paging yields)로 교체함 (함정 #1, 제가 제안한 가상 패치보다 더 진전된 방식)
- #114358: 하나의 카탈로그 요청 내에서 중복 열거 (duplicate enumeration)를 제거함
두 가지 핵심 발견 사항 모두 병합된 업스트림 (upstream) 코드에 의해 독립적으로 확인되었습니다. 수정된 형태는 보고서의 권장 사항과 일치했습니다.
제가 "내가 맞혔다"라고 말하는 것이 아닙니다. 제가 하고 싶은 말은, 본인의 인시던트 (incident)로부터 추상화한 분류가 메인 (main) 브랜치에 코드를 병합하는 타인들에 의해 검증될 때 느끼는 기묘하고도 확신에 찬 기분이 있다는 것입니다. 이는 그 어떤 마케팅 수치보다 값진 경험입니다.
만약 에이전트 시스템을 운영 중이며, 여러분의 시스템에 다음과 같은 세 가지 보이지 않는 충돌 위험 요소 — 멱등성 가드 (idempotency guards), 재시도 정책 (retry policy), 로깅 (logging) — 가 있는지 알고 싶다면, ARK에서 회원가입 없이 30초 만에 무료로 정적 점검을 수행할 수 있습니다:
🔗 https://ark-6ek.pages.dev/diagnose
그리고 만약 새벽 3시에 '충돌-재시작-충돌'의 루프를 경험해 본 적이 있다면, 댓글로 알려주세요. 아마 저도 정확히 당신과 같은 유형을 겪어봤을 확률이 높습니다.
(공개된 GitHub 이슈에 대한 기술적 분석이며, OpenClaw 프로젝트와는 관련이 없습니다.)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기