cron배치backend
크론 작업 설계 — 멱등성이 전부다
✨ AI 요약
긴 글, 핵심만 먼저 — 이 글을 3줄로 정리해드려요.
조회 32
크론 작업은 "한 시간에 한 번 실행된다"고 믿고 짜기 쉽다. 현실은 다르다. 겹쳐 돌고, 건너뛰고, 중간에 죽는다. 이 셋을 전제하고 설계하면 크론은 평화롭다.
전제 1 — 두 번 실행된다
재시도, 배포 중 중복 스케줄, 수동 실행… 같은 작업이 두 번 돌 경로는 얼마든지 있다. 대응은 멱등성: 몇 번 실행해도 결과가 같게.
// 나쁨: 실행마다 insert — 두 번 돌면 두 배
await db.insert(rows);
// 좋음: 자연키 기준 upsert — 몇 번 돌아도 동일
for (const row of rows) {
await db.upsert({ where: { url: row.url }, create: row, update: {...} });
}
수집기, 정산, 알림 발송 — 전부 "이미 처리했는가"를 데이터로 판별할 수 있어야 한다.
전제 2 — 겹쳐 돈다
이전 실행이 안 끝났는데 다음 스케줄이 온다. 같은 데이터를 두 프로세스가 만지면 멱등성으로도 못 막는 경합이 생긴다.
- 앱 레벨: 실행 시작 시 락 획득 (Postgres advisory lock, Redis SET NX)
- 인프라 레벨: GitHub Actions라면 concurrency 그룹, K8s CronJob이라면 concurrencyPolicy: Forbid
락은 반드시 만료 시간을 두자. 락 잡고 죽은 프로세스가 영원히 다음 실행을 막는 게 최악의 시나리오다.
전제 3 — 안 돈다
크론이 조용히 멈추는 건 흔한 장애다(스케줄러 장애, 큐 정체, 잘못된 배포). 문제는 아무 일도 안 일어나서 아무도 모른다는 것.
- 각 실행이 끝날 때 "마지막 성공 시각"을 기록
- 그 시각이 주기의 2배를 넘으면 알림 (헬스체크 서비스나 간단한 모니터링 쿼리로)
- 실패 알림보다 부재 알림이 크론에선 더 중요하다
보너스 — 시간대
서버는 UTC, 사용자는 KST. "매일 자정 정산"의 자정이 어느 자정인지 코드에 명시하자. DST 없는 한국만 서비스해도, 클라우드 스케줄러는 UTC 기준이다.
멱등성 · 중복 방지 · 부재 감지. 크론의 신뢰성은 이 세 단어로 요약된다.