우분투 실전 명령어 | flock으로 스크립트 중복 실행 막기
언제 쓰는가
백업, 배치 수집, 로그 정리 같은 크론 작업이 실행 시간이 길어질 때 자주 씁니다.
이전 실행이 끝나기 전에 다음 주기가 겹치면 파일 충돌이나 중복 적재가 생기는데, flock으로 바로 막을 수 있습니다.
바로 쓰는 명령어
flock -n /var/lock/report-sync.lock /usr/local/bin/report-sync.sh
#!/usr/bin/env bash
set -euo pipefail
lock_file="/var/lock/inventory-refresh.lock"
exec 9>"$lock_file"
if ! flock -n 9; then
echo "이미 실행 중입니다. 이번 주기는 건너뜁니다."
exit 0
fi
/usr/local/bin/inventory-refresh --target prod
핵심 옵션/패턴
- -n: 잠금을 바로 시도하고 실패하면 즉시 종료합니다. 크론 중복 방지에 가장 많이 씁니다.
- -w 초: 지정한 시간만큼 기다렸다가 잠금을 못 잡으면 종료합니다. 짧은 지연 허용 배치에 유용합니다.
- 잠금 파일은 경로만 같으면 됩니다. 파일 내용보다 같은 파일 디스크립터를 공유하는지가 핵심입니다.
- 스크립트 안에서 exec 9>lockfile 뒤 flock 9 패턴을 쓰면, 스크립트 종료 시 잠금이 자동 해제되어 관리가 편합니다.
# 최대 15초까지 대기 후 실행
flock -w 15 /var/lock/daily-etl.lock /usr/local/bin/daily-etl.sh
# 명령 블록 전체를 잠금으로 감싸기
flock -n /var/lock/cache-warm.lock bash -lc '
/usr/local/bin/cache-warmup step1
/usr/local/bin/cache-warmup step2
'
명령 출력 예시
$ flock -n /var/lock/report-sync.lock /usr/local/bin/report-sync.sh
이미 실행 중입니다. 이번 주기는 건너뜁니다.
$ flock -w 5 /var/lock/daily-etl.lock /usr/local/bin/daily-etl.sh
[INFO] lock acquired
[INFO] extract started
[INFO] load finished
자주 하는 실수
- 잠금 파일 경로를 작업마다 다르게 써서 사실상 잠금이 안 걸리는 경우가 많습니다.
- flock 없이 pid 파일만 만들고 비정상 종료 정리를 안 해서 영구 차단 상태가 되는 경우가 있습니다.
- sudo 유무가 섞여 lock 파일 권한이 바뀌면 다음 실행에서 잠금을 못 잡거나 파일 생성이 실패할 수 있습니다.
- 잠금은 걸었지만 실제로는 서브프로세스를 백그라운드로 분리해 중복 실행이 다시 생기는 경우가 있습니다.
검증 방법
# 터미널 1
flock /tmp/demo.lock bash -lc 'echo "T1 lock"; sleep 20; echo "T1 done"'
# 터미널 2 (즉시 실패 확인)
flock -n /tmp/demo.lock bash -lc 'echo "T2 lock"' || echo "T2 failed as expected"
# 크론 대상 스크립트 단위 검증
for i in 1 2 3; do
flock -n /tmp/job.lock bash -lc 'date "+%F %T"; sleep 3' &
done
wait
정상이라면 동시에 여러 개를 띄워도 실제 본문 작업은 한 번만 실행됩니다.
운영 팁
잠금 파일 이름에 서비스명을 넣고, /var/lock 또는 /run/lock 아래로 위치를 통일하면 운영 중 추적이 쉬워집니다.
장시간 작업에는 -w를 짧게 두고 실패 로그를 남겨서, 지연 누적보다 스킵을 선택하는 정책을 먼저 정하는 게 안전합니다.
출처
- util-linux man pages
- Ubuntu Server Guide
- Debian Administrator's Handbook