매일 아침 9시 40분, 사흘째 같은 실패인데 이유는 매번 달라 보였습니다 🔁

며칠 몸이 찌뿌둥할 때, 첫날은 “어제 잠을 잘못 잤나 보다” 하고 넘어갑니다. 둘째 날도 비슷하면 “환절기라 그런가” 합니다. 그런데 셋째 날마저 똑같으면 그제야 “이거 며칠째 같은 거 아닌가” 하고 병원을 찾습니다. 하루하루는 각자 다른 핑계가 있어 보이는데, 사흘이 쌓이면 그 핑계들이 사실 하나였다는 게 드러납니다. 제 블로그 자동 예약발행도 딱 이 순서로 문제가 드러났습니다. 다른 건, 저 대신 그 사흘을 매일 아침 비교해준 게 제가 만들어둔 헬스체크 에이전트였다는 겁니다.
1일차 — UI가 이상한 줄 알았다
이 블로그는 네이버판 예약발행을 맥미니에서 매일 아침 9시 40분 자동으로 시도합니다. 9월 10일, 이 작업이 실패했습니다. 로그를 보니 카테고리 드롭다운에서 “만들면서 배운 것” 항목을 못 찾고, 달력도 안 열렸습니다. 흔한 화면 렌더링 타이밍 문제로 보였습니다. 그날 헬스체크 리포트도 “UI 오류”로만 기록하고 넘어갔습니다.
2일차 — 다른 증상, 그래서 다른 사고로 봤다
9월 11일, 같은 작업이 또 실패했습니다. 이번엔 로그에 STATUS: error session_expired라고 찍혀 있었습니다. 어제는 화면 요소를 못 찾은 거였고, 오늘은 로그인 세션이 끊긴 겁니다. 증상이 다르니 헬스체크 리포트도 “원인 서로 다른 2일 연속 실패라 트렌드로 단정하긴 이르다”고 판단했습니다. 저도 이 판단을 그대로 받아들였습니다. 이틀 연속 실패라도, 서로 다른 사고면 우연이 두 번 겹친 것뿐일 수 있으니까요.
3일차 — 그제야 같은 문제라는 게 확정됐다

9월 12일, 세 번째 실패가 났습니다. 로그를 보니 또 session_expired. 하루 전과 완전히 같은 에러였습니다. 여기서 헬스체크 리포트의 판단이 바뀌었습니다. “어제는 원인이 다르다고 봤지만, 오늘도 같은 세션 만료가 재발해 네이버 로그인 세션이 자동 갱신되지 않는 근본 문제로 무게가 이동한다.” 하루씩 떼어놓고 보면 “다른 사고 두 번”이었던 것이, 사흘치를 나란히 놓고 보니 “같은 사고 두 번 + 원인 불명 한 번”으로 다시 읽힌 겁니다. 판단을 바꾼 근거는 새로운 정보가 아니라, 어제 기록과 오늘 기록을 나란히 놓고 비교한 것뿐이었습니다.
더 큰 문제 — 실패는 스스로 다시 시도하지 않는다
세션 문제보다 제가 더 놀란 건 따로 있었습니다. 이 예약발행 스크립트는 그날 발행 예정인 초안, 그러니까 publish_date가 딱 오늘 날짜인 것만 찾아서 시도하도록 짜여 있었습니다. 그 말은, 9월 10일 발행 예정이던 초안이 그날 실패하면 9월 11일에는 그 초안을 다시 시도하지 않는다는 뜻입니다. 스크립트 입장에서 그 초안의 발행일은 이미 지나간 날짜니까요. 사흘 동안 실패가 쌓이면서, 발행 예정이었지만 끝내 못 나간 초안도 그대로 세 건이 쌓였습니다. 자동화를 만들 때는 “오늘 실패하면 내일 또 시도하겠지”라고 막연히 생각했는데, 실제로 짜놓은 조건은 “오늘 몫은 오늘만” 이었던 겁니다.
로그를 뒤쫓다가 하나 더 걸렸습니다. launchd가 표준 에러를 남기기로 되어 있는 로그 파일은 8월 13일 이후로 갱신이 멈춰 있었습니다. 처음엔 “이 작업 자체가 8월부터 죽어 있었나” 싶어 순간 아찔했는데, 알고 보니 스크립트 안에서 자체적으로 실제 로그를 다른 경로로 다시 리다이렉트하고 있었습니다. launchd가 가리키는 로그와 스크립트가 실제로 쓰는 로그가 서로 다른 파일이었던 거죠. 겉으로 멈춘 것처럼 보이는 로그를 보고 “작업이 멈췄다”고 오판할 뻔한 순간이었습니다.
하루하루는 서로 다른 사고처럼 보였지만, 사흘을 나란히 놓고 나서야 하나의 문제였다는 게 드러났습니다.
따라 하기
혼자 자동화를 여러 개 돌리다 보면 “실패하면 알림은 온다”까지만 만들어두고 “그다음엔 어떻게 되는가”는 안 정해두기 쉽습니다. 저는 이번 일로 아래 세 가지를 점검 순서에 넣었습니다.
1. launchd가 가리키는 로그를 곧이곧대로 믿지 않는다
launchctl list | grep <routine-이름>
grep -n "exec >>" <스크립트-경로>.sh
launchctl list의 exit code부터 확인하되, 그 작업의 plist가 지정한 로그 파일이 실제로 갱신되고 있는지mtime도 같이 봅니다. 스크립트 안에서exec >>로 자체 리다이렉트를 하고 있으면 launchd 쪽 로그는 멈춘 것처럼 보여도 정상일 수 있습니다. 진짜 로그 위치는 스크립트 안을 직접 검색해서 찾습니다.
2. 어제와 오늘의 실패 로그를 나란히 비교한다
diff <(tail -5 logs/<작업명>-$(date -v-1d +%F).log) <(tail -5 logs/<작업명>-$(date +%F).log)
- 하루치만 보면 “어제와 다른 이유네” 하고 넘어가기 쉽습니다. 최근 2~3일치를 나란히 diff로 비교하면, 실은 같은 에러 문자열이 반복되는지 아니면 정말 매번 다른 사고인지가 바로 보입니다.
3. “오늘 조건”만으로 짜인 재시도 로직이 있는지 확인한다
grep -n "publish_date ==" <스크립트-경로>.sh
- 예약·재시도 스크립트가 “발행일이 오늘인 것”만 찾도록 짜여 있다면, 실패한 날짜의 몫은 다음 날 자동으로 다시 시도되지 않습니다. 지난 날짜 몫까지 훑는 catch-up 조건이 있는지 없는지부터 확인합니다.
✅ 이렇게 되면 성공 — 로그 위치·최근 며칠 비교·재시도 조건 세 가지를 확인했을 때, 실패가 “반복되는 패턴”인지 “우연히 겹친 별개 사고”인지 스스로 답할 수 있으면 됩니다.
⚠️ 막히면 — 재시도 조건이 “오늘”로만 짜여 있는 걸 발견했다면, 원인(세션 만료 등)을 고치는 것과 별개로 밀린 몫을 처리하는 절차(수동 재예약 또는 catch-up 로직 추가)를 반드시 정해둡니다. 원인만 고치고 밀린 세 건을 그대로 두면, 다음에 또 실패했을 때 같은 방식으로 계속 쌓입니다.
배운 것

이번에 배운 건 “네이버 세션이 자주 끊긴다”가 아닙니다. 실패 알림까지만 만들어두고 그 뒤를 안 정해두면, 자동화는 실패한 순간부터 자기 힘으로는 절대 복구되지 않는다는 겁니다. 하루치 로그만 보면 매번 다른 사고처럼 보이는 것도, 사람이 매일 들여다보지 않아도 어제와 오늘을 대신 나란히 놓고 비교해주는 장치 하나만 있으면 사흘 만에 패턴으로 잡힌다는 것도 함께 배웠습니다. 다음엔 자동화를 만들 때 “실패하면 알려줘”까지가 아니라 “실패한 몫은 언제, 어떻게 다시 시도할지”까지 같이 정해두려고 합니다.
오늘도 한 걸음. 🐴
이 글은 산업 구조와 만드는 과정을 정리한 개인 기록입니다.
특정 종목의 매수·매도 추천이 아니며, 투자 판단과 그 결과는 독자 본인에게 있습니다.