Cron Jobs가 조용히 실패하는 이유 (그리고 해결 방법)

발행: (2026년 3월 7일 AM 07:37 GMT+9)
8 분 소요
원문: Dev.to

Source: Dev.to

당신의 데이터베이스 백업은 매일 새벽 2 시에 실행됩니다. 청구서 생성기는 매주 월요일 아침에 작동합니다. 캐시 워머는 5분마다 실행됩니다. 모두 잘 동작합니다—하지만 문제가 생기면 그렇지 않죠.

크론 작업의 문제는 조용히 실패한다는 점입니다. 새벽 2 시에 stdout을 보는 사람은 없습니다. 오류 페이지를 보여줄 브라우저도 없죠. 크론 작업이 멈추면, 유일한 신호는 뭔가가 일어나지 않는다는 사실뿐입니다.

당신은 금요일 오후에 백업이 화요일부터 실행되지 않았다는 것을 발견합니다. 고객이 주간 보고서가 도착하지 않았다고 이메일을 보냅니다. 혹은 정리 작업이 3주 전에 죽었음에도 디스크가 가득 찹니다.

크론 작업이 조용히 실패하는 이유

일반적인 원인

  • Server reboots – 재부팅 후에는 일반적으로 크론이 다시 시작되지만, 작업이 마운트된 볼륨, 실행 중인 데이터베이스, 혹은 초기화에 몇 초가 걸리는 네트워크 연결에 의존한다면 재부팅 직후 첫 실행이 조용히 실패합니다.
  • Disk full – 작업이 임시 파일이나 로그를 쓰려고 시도하지만 못하고 충돌합니다. 크론은 전혀 신경 쓰지 않습니다.
  • Dependency failures – 호출하려는 API가 다운되었거나, 데이터베이스 연결이 타임아웃되었거나, S3 버킷 정책이 변경되었습니다. 작업이 예외를 발생시키고 비‑제로 코드로 종료되지만, 아무도 눈치채지 못합니다.
  • Timezone issues – UTC 서버에 배포했지만 미국 동부 시간을 기준으로 크론 표현식을 작성했습니다. 작업이 잘못된 시간에 실행되거나, DST 전환 시 두 번 실행되거나 전혀 실행되지 않을 수 있습니다.
  • Early crashes – 오류 처리가 catch 블록에 도달할 만큼 충분히 오래 실행돼야 한다면, 초기 세그멘테이션 오류나 OOM 킬로 인해 실패 증거가 전혀 남지 않습니다.

전통적인 모니터링이 이를 놓치는 이유

대부분의 모니터링 도구는 active 증상—높은 CPU 사용량, 응답 지연, 오류율 급증—을 감시합니다. 현재 일어나고 있는 일을 포착하는 데는 뛰어나죠.

크론 작업 실패는 passive—무언가가 일어나지 않는 상황—입니다. APM은 스크립트가 실행되지 않았다는 사실을 알리지 않으며, 오류 추적기는 시작조차 하지 않은 프로세스에서 발생한 예외를 캡처할 수 없습니다.

해결책: 모델 전환

실패를 감시하는 대신 성공이 없음을 감시합니다. 이는 본질적으로 데드맨 스위치 혹은 하트비트 모니터링과 같습니다.

  1. 예상 간격(예: “매 24 시간”)을 설정한 모니터를 생성합니다.
  2. 작업의 끝에 을 추가합니다.
  3. 핑이 제때 도착하지 않으면 알림을 받습니다.

핵심 인사이트: 작업이 실패했는지를 모니터링하는 것이 아니라 작업이 성공했는지를 모니터링한다는 점입니다. 만약 작업으로부터 응답이 없으면 무언가 잘못된 것이며, 정확히 무엇이 문제인지는 알 필요가 없습니다.

이를 구현하는 간단한 방법은 스크립트 끝에 단일 HTTP 요청을 추가하는 것입니다. 스크립트가 정상적으로 완료되면 핑이 전송됩니다. 스크립트가 충돌하거나, 멈추거나, 시작조차 하지 않으면 핑이 전송되지 않아 알림을 받게 됩니다.

구현 예시

Bash

#!/bin/bash
# backup-database.sh

set -e  # Exit on any error

pg_dump "$DATABASE_URL" | gzip > /tmp/backup.sql.gz
aws s3 cp /tmp/backup.sql.gz s3://my-backups/$(date +%Y-%m-%d).sql.gz
rm /tmp/backup.sql.gz

# Report success
curl -fsS --retry 3 https://pulsemon.dev/api/ping/nightly-backup

set -e 플래그는 오류가 발생하면 스크립트를 종료합니다. curl오직 위의 모든 작업이 성공했을 때만 실행되며, 그렇지 않으면 ping이 전송되지 않습니다.

Python

import requests

def main():
    # ... your job logic here ...
    run_etl_pipeline()
    requests.get("https://pulsemon.dev/api/ping/nightly-etl", timeout=10)

if __name__ == "__main__":
    main()

Node.js

const fetch = require('node-fetch');

async function main() {
  // ... your job logic here ...
  await processQueue();
  await fetch('https://pulsemon.dev/api/ping/queue-processor');
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

심장 박동이 필요한 일반적인 무인 프로세스

  • Database backups – 가장 흔한 무음 실패.
  • Email queues – 처리가 중단되어도 사람들이 정상이라고 생각해 며칠 동안 불평이 없습니다.
  • Data syncs between services – 오래된 분석 대시보드가 겉보기엔 괜찮아 보입니다.
  • Certificate renewals (e.g., Let’s Encrypt) – 만료된 인증서는 무서운 브라우저 경고를 발생시킵니다.
  • Cleanup jobs that free disk space – 이 작업이 중단되면 다른 서비스가 충돌하기 시작합니다.

이 중 하나라도 인프라에서 실행되고 있다면, 심장 박동 모니터를 설정해야 합니다. 설정하는 데 드는 시간은 장애 복구에 소요되는 시간보다 훨씬 적습니다.

PulseMon 사용해 보기

저는 제 프로젝트에서 이 문제를 해결하기 위해 PulseMon을 만들었습니다. 사용해 보고 싶다면 30개의 모니터를 제공하는 무료 티어가 있습니다:

PulseMon.dev

0 조회
Back to Blog

관련 글

더 보기 »

출시를 줄이고, 측정을 늘리세요

AI는 엔지니어링 병목 현상을 없애지 못했다 – 단지 위치를 옮겼을 뿐이다. Code는 그 어느 때보다 저렴해졌다. 프로토타입은 몇 시간 안에 나타나고, 한때 몇 주가 걸리던 복잡한 시스템도 …