본문으로 건너뛰기
개발 머꼬
개발 노트인프라·운영
hohyeon.dev20

cron 배치가 겹쳐 돌면서 같은 메일을 두 번 보낸 이유

  • #Engineering Note
  • #인프라·운영

문제 발생

5분마다 도는 알림 배치가 평소에는 30초에 끝났는데, 외부 API가 느려진 날 6분이 걸렸습니다. 그날 사용자들이 같은 알림을 두 번 받았습니다.

*/5 * * * * /usr/local/bin/send-notifications.sh

시간이 더 밀리자 프로세스가 셋, 넷씩 쌓여 서버 부하까지 올라갔습니다.

원인 분석

cron은 스케줄만 봅니다. 이전 실행이 아직 돌고 있는지 확인하지 않고, 시간이 되면 새 프로세스를 띄웁니다. 실행 시간이 주기보다 길어지는 순간 중첩이 시작되고, 부하가 올라가면 더 느려져서 더 겹치는 악순환이 됩니다.

애플리케이션에서 "실행 중 플래그"를 파일이나 DB에 두는 방식은 흔하지만, 프로세스가 비정상 종료하면 플래그가 남아 다음 실행이 영영 막힙니다.

리눅스에는 이 용도의 도구가 있습니다. flock(1)셸 스크립트나 명령행에서 flock(2) 잠금을 관리하는 유틸리티입니다. 커널이 파일 디스크립터에 잠금을 걸기 때문에 프로세스가 죽으면 잠금도 함께 풀립니다 — 남는 플래그 문제가 구조적으로 없습니다.

해결 방안

  1. cron 항목을 flock으로 감쌉니다. -n은 문서 설명대로 잠금을 즉시 얻을 수 없으면 기다리지 않고 실패합니다.
*/5 * * * * /usr/bin/flock -n /var/lock/notify.lock /usr/local/bin/send-notifications.sh
  1. 스크립트가 스스로 잠그게 할 수도 있습니다. man 페이지가 제시하는 관용구로, 어디서 실행되든 중복이 막힙니다.
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
  1. "건너뜀"을 오류로 취급하지 않습니다. -n으로 실패하면 종료 코드가 1입니다(문서의 기본값). 모니터링이 이걸 장애로 잡지 않도록 -E 옵션으로 충돌 전용 종료 코드를 따로 주는 방법도 있습니다.
flock -n -E 75 /var/lock/notify.lock ./job.sh
  1. 겹침을 로그로 남깁니다. 조용히 건너뛰기만 하면 "왜 알림이 안 갔지"를 나중에 추적할 수 없습니다. 건너뛴 횟수는 배치가 주기를 못 맞추고 있다는 신호이기도 합니다.

  2. 여러 서버에서 도는 배치라면 파일 잠금으로는 부족합니다. 호스트별 잠금이므로 클러스터 전체에는 Redis 락이나 DB 락이 필요합니다.

  3. systemd timer도 검토합니다. 같은 서비스 유닛이 이미 실행 중이면 다시 시작하지 않으므로 중첩 방지가 기본으로 따라옵니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.