13일간의 침묵: 하나의 잘못된 초안이 전체 DM 채널을 멈추게 한 방법
요약
자동 DM 채널 운영 중 발생한 '설계적 결함'으로 인해 13일간 메시지 전송이 완전히 멈춘 사례를 분석합니다. 단순히 종료 코드를 확인하는 것만으로는 시스템의 실제 상태를 파악하기 어려우며, 실패 원인을 근본적으로 해결해야 함을 강조합니다.
핵심 포인트
- 단순한 오류 로그(process.exit)는 '작동함'을 의미하지 않는다.
- 실패가 발생했을 때 Discord 알림 등 외부 모니터링이 필수적이다.
- 큐의 맨 앞에 고정된 실패 항목이 전체 프로세스를 멈추게 할 수 있다.
지난번에는 컴퓨터 사용 승인 대화 상자를 자동 클릭하는 터미널 감시 데몬에 대해 글을 썼습니다. 이번 포스트도 같은 장르, 즉 조용히 죽어가는 방치된 작업에 관한 것이지만, 원인이 모니터링의 공백이 아니었습니다. 바로 설계 자체였습니다. founder-scout의 자동 DM 채널은 단 하나의 잘못된 기록 때문에 13일 동안 단 하나의 메시지도 보내지 않았고, 아무도 알아채지 못했습니다.
문제점: 종료 코드는 있었지만, 아무도 보지 못했다
founder-scout에는 @bokuwalily의 새 팔로워에게 첫 DM을 보내는 followers 채널이 있습니다. 제가 2026년 9월 10일에 확인했을 때, 마지막 성공적인 전송은 8월 28일 16:35였습니다. 13일 동안 단 하나의 DM도 없었습니다.
큐(state/followers_queue.jsonl)는 실행할 때마다 336개 항목에서 390개로 계속 증가했습니다. 다시 말해, 매일 초안이 생성되고 전송 스크립트가 매일 실행되었습니다. 하지만 여전히 전송은 '0'이었습니다. 로그에는 날마다 process.exit(3)이 기록되었지만, 이 중단 경로는 Discord 알림과 연결되지 않았기 때문에 아무도 눈치채지 못했습니다.
근본 원인:
근본 원인:
참고
같은 날,dm.mjs측에서도 비슷한 형태의 다른 사고가 발생했습니다. 동일한 세 사람에 대한 Composer 타임아웃이 세 번 연속 실패로 계산되어 스톱 가드(stop guard)를 작동시켰고, 그 뒤에 있던 네 명은 두 번 연속으로 전송되지 못했습니다. 원인은 다르지만 패턴은 같습니다: 큐의 맨 앞에 있는 항목이 고정된다 → 매번 여기서 작업이 멈춘다.
Fail-closed는 _그 하나의 기록_을 멈추기 위함입니다
이것이 교훈입니다. 숫자 게이트(number-gate)나 Composer 유효성 검사 같은 사전 전송 확인 절차는 위험한 메시지 하나가 나가는 것을 막기 위해 존재합니다. 하지만 만약 이를
다른 수정 사항은 세 번 연속 실패 방지(consecutiveFailures >= 3일 때 break)가 매번 같은 사용자에게만 계속 적용되는 것을 막기 위한 재정렬입니다.
// src/followers_send.mjs:81-83
// 한 번 실패한 사용자는 뒤로 보낸다. 맨 앞의 같은 몇 명이 매 실행마다 실패하면 '3회 연속 실패로 중지'에 걸려,
// 뒤에 있는 보내기 가능한 사용자들까지 함께 영향을 받는다 (실측 2026-09-10: 같은 3명으로 2회 연속 0건).
...
이 코드는 단순히 attempts (과거 전송 시도 횟수)를 오름차순으로 정렬합니다. 이제 구조적으로 계속 실패할 운명에 놓인 사용자들—DM을 열지 않거나, composer가 시간 초과되는 경우—이 더 이상 대기열의 맨 앞을 독점하지 않으며, 그 뒤에 있는 전송 가능한 사용자들도 매 실행마다 함께 영향을 받지 않습니다.
모니터링: 종료 코드만으로는 '작동한다'는 의미가 아니다
이 문제가 13일 동안 감지되지 않은 이유는 오류로 중단된 경로의 로그가 로컬에만 존재했기 때문입니다. launchctl list나 pm2 list에서
- 단일 이상 징후에 대해
process.exit(3)를 설계하는 것 → 기록되지 않은 이상 징후는 대기열 맨 앞에 주차된 채로 남아 레인이 영구적으로 멈춥니다. - 어보트 경로에 Discord 알림을 연결하는 것을 잊은 것 → 아무도 읽지 않는 로그의 종료 코드는 침묵과 같습니다.
- 드롭된 행(dropped row)을 원장(ledger)에 기록하지 않고 건너뛰는 것 → 다음 실행 시 동일한 초안을 같은 위치에서 재평가하고 매번 그 지점에서 멈춥니다.
- 세 번 연속 실패 방지 장치가 매번 고정된 사람들에게 작동하는 것 → 단순히 실패 이력이 있는 사람들을 맨 뒤로 이동시키면, 그들 뒤에 있는 발송 가능한 사람들은 함께 중단되는 것을 막을 수 있습니다.
- **
launchctl list의 로드 상태만으로
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기