배포할 때마다 크론 항목이 하나씩 늘어 정리 작업이 여러 번 돌던 문제
문제 발생
삭제된 글을 30일 뒤 지우는 정리 작업을 배포 스크립트가 크론에 등록하게 했습니다.
(crontab -l; echo "17 4 * * * docker compose run --rm migrate pnpm db:purge") | crontab -몇 주 뒤 crontab -l을 보니 같은 줄이 배포 횟수만큼 쌓여 있었습니다. 정리 작업이 새벽마다 열두 번씩 돌고 있었고, 같은 시각에 겹쳐 돌면서 컨테이너를 열두 개 띄웠습니다.
원인 분석
crontab은 항목을 추가하는 명령이 아니라 표를 통째로 설치하는 명령입니다. man 페이지의 개요가 그대로입니다 — crontab [-u user] <file | ->는 파일(또는 표준 입력 -)을 현재 crontab으로 설치하고, -l은 현재 crontab을 표준 출력으로 보여 줍니다.
위 명령은 "현재 표 전체 + 새 줄 한 개"를 다시 설치합니다. 기존에 같은 줄이 있는지 보지 않으니 실행할 때마다 한 줄이 늘어납니다. 사람이 crontab -e로 편집할 때는 눈으로 중복을 걸러 내지만, 스크립트에는 눈이 없습니다.
겹쳐 도는 것은 두 번째 문제입니다. cron은 이전 실행이 끝났는지 확인하지 않습니다. 열두 줄이 같은 시각이면 열두 개가 동시에 시작합니다.
해결 방안
- 우리 줄에 표식을 달고, 넣기 전에 그 표식이 있는 줄을 걷어냅니다. 몇 번을 실행해도 결과가 같습니다.
MARK='# meokko-cleanup'
LINE="17 4 * * * cd /srv/meokko && docker compose run --rm migrate pnpm db:purge >> /srv/meokko/cleanup.log 2>&1 $MARK"
{ crontab -l 2>/dev/null | grep -v " $MARK\$" || true; echo "$LINE"; } | crontab -crontab -l은 crontab이 아직 없으면 오류로 끝나므로 2>/dev/null과 || true가 필요합니다. 그러지 않으면 첫 배포에서 파이프가 깨집니다.
-
다른 사람의 줄은 건드리지 않습니다. 표식이 있는 줄만 걷어내므로 같은 서버의 다른 작업은 그대로 남습니다.
crontab file로 우리 파일을 통째로 설치하면 그 작업들이 사라집니다. -
-r을 스크립트에 쓰지 않습니다. man 페이지대로-r은 현재 crontab을 통째로 제거합니다.-e와 키 하나 차이라 손으로도 위험한 옵션입니다. -
겹치면 안 되는 작업은 스스로 잠급니다. 표식으로 중복 등록을 막아도, 작업이 하루보다 오래 걸리면 다음 실행과 겹칩니다. 작업 명령을
flock -n /tmp/cleanup.lock …으로 감싸면 이전 실행이 끝나기 전에는 시작하지 않습니다. -
등록된 결과를 배포 로그에 남깁니다. 마지막에
crontab -l | grep "$MARK"를 출력해 두면 배포 로그만 보고도 몇 줄이 들어갔는지 알 수 있습니다. 하나여야 합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.