때로는 하나의 쉘 스크립트 인스턴스 만 동시에 실행되고 있는지 확인해야합니다.
예를 들어 자체 잠금 기능을 제공하지 않는 크론을 통해 실행되는 크론 작업 (예 : 기본 Solaris 크론).
잠금을 구현하는 일반적인 패턴은 다음과 같은 코드입니다.
#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then # 'test' -> race begin
echo Job is already running\!
exit 6
fi
touch $LOCK # 'set' -> race end
# do some work
rm $LOCK
물론 이러한 코드에는 경쟁 조건이 있습니다. 두 번째 인스턴스의 실행이 $LOCK
파일 을 터치하기 전에 3 행 이후에 진행될 수있는 시간 창이 있습니다.
크론 작업의 경우 두 호출 사이에 분 간격이 있으므로 일반적으로 문제가되지 않습니다.
그러나 잠금 파일이 NFS 서버에있을 때와 같이 상황이 잘못 될 수 있습니다. 이 경우 여러 cron 작업이 3 행에서 차단되어 대기 할 수 있습니다. NFS 서버가 다시 활성화 된 경우 병렬로 실행중인 작업 무리 가 있습니다.
웹에서 검색 하면 해당 문제에 대한 좋은 해결책 인 것처럼 보이는 도구 lockrun 을 발견했습니다 . 그것으로 당신은 다음과 같이 잠금이 필요한 스크립트를 실행합니다 :
$ lockrun --lockfile=/var/tmp/mylock myscript.sh
이것을 랩퍼에 넣거나 crontab에서 사용할 수 있습니다.
사용 lockf()
가능한 경우 (POSIX)를 사용하고 flock()
(BSD)로 폴백합니다. 그리고 lockf()
NFS를 통한 지원은 비교적 광범위해야합니다.
대안이 lockrun
있습니까?
다른 크론 데몬은 어떻습니까? 제정신 방식으로 잠금을 지원하는 공통 크론이 있습니까? Vixie Crond (데비안 / 우분투 시스템의 기본값) 매뉴얼 페이지를 잠깐 살펴보면 잠금에 관한 내용이 표시되지 않습니다.
이 같은 도구를 포함하는 것이 좋습니다 있을까 lockrun
에 로 coreutils를 ?
내 의견으로는 timeout
, nice
및 친구와 매우 유사한 주제를 구현합니다 .
답변
쉘 스크립트에서 잠금을 수행하는 또 다른 방법은 위에서 설명한 경쟁 조건을 방지 할 수 있으며 두 작업이 모두 행 3을 통과 할 수 있습니다.이 noclobber
옵션은 ksh 및 bash에서 작동합니다. set noclobber
csh / tcsh에서 스크립팅해서는 안되므로 사용하지 마십시오 . 😉
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
NFS에 잠금 기능이있는 YMMV (NFS 서버에 연결할 수없는 경우)는 일반적으로 예전보다 훨씬 강력합니다. (10 년 전)
여러 서버에서 동시에 동일한 작업을 수행하는 크론 작업이 있지만 실제로 실행하기 위해 인스턴스가 하나만 있으면이 작업이 효과적 일 수 있습니다.
lockrun에 대한 경험은 없지만 스크립트를 실제로 실행하기 전에 미리 설정된 잠금 환경이 있으면 도움이 될 수 있습니다. 아니면 그렇지 않을 수도 있습니다. 당신은 래퍼에서 스크립트 외부의 잠금 파일에 대한 테스트를 설정하고 있으며 이론적으로는 두 개의 작업이 정확히 동일한 시간에 lockrun에 의해 호출 된 경우 ‘inside- 스크립트 솔루션?
파일 잠금은 어쨌든 시스템 동작을 거의 존중하며, 실행 전에 잠금 파일의 존재를 확인하지 않는 스크립트는 무엇이든 할 것입니다. 잠금 파일 테스트와 적절한 동작을 수행하면 100 %가 아니라도 99 %의 잠재적 문제를 해결할 수 있습니다.
잠금 파일 경쟁 조건이 많이 발생하는 경우 작업 시간이 제대로 지정되지 않았거나 작업 완료만큼 간격이 중요하지 않은 경우보다 큰 문제를 나타내는 것일 수 있습니다. .
아래 편집-2016-05-06 (KSH88을 사용하는 경우)
아래 @Clint Pachl의 의견을 바탕으로 ksh88을 사용 mkdir
하는 경우 대신을 사용하십시오 noclobber
. 이것은 대부분 잠재적 인 경쟁 조건을 완화하지만 완전히 제한하지는 않습니다 (위험은 미미합니다). 자세한 내용 은 아래 Clint가 게시 한 링크를 참조하십시오 .
lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid
if ( mkdir ${lockdir} ) 2> /dev/null; then
echo $$ > $pidfile
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -rf "$lockdir"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi
또한 스크립트에서 tmpfile을 작성해야하는 경우 스크립트 종료시 lockdir
정리 될 것임을 알고 디렉토리를 사용할 수 있습니다 .
보다 현대적인 bash의 경우 상단의 noclobber 방법이 적합해야합니다.
답변
하드 링크를 선호합니다.
lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
echo locked
else
echo locked by $(<$lockfile)
rm $tmpfile
exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to
하드 링크는 NFS를 통한 원 자성 이며 대부분의 경우 mkdir도 마찬가지 입니다. 실제적인 수준에서 사용 mkdir(2)
하거나 link(2)
거의 동일; NFS보다 많은 구현이 atomic보다 atomic hard link를 허용했기 때문에 하드 링크를 선호합니다 mkdir
. 최신 NFS 릴리스를 사용하면 둘 중 어느 것을 사용해도 걱정할 필요가 없습니다.
답변
나는 그것이 mkdir
원자 적이라는 것을 이해합니다 .
lockdir=/var/tmp/myapp
if mkdir $lockdir; then
# this is a new instance, store the pid
echo $$ > $lockdir/PID
else
echo Job is already running, pid $(<$lockdir/PID) >&2
exit 6
fi
# then set traps to cleanup upon script termination
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15
답변
쉬운 방법은 패키지 lockfile
와 함께 제공되는 것 procmail
입니다.
LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0
# here the actual job
rm -f "$LOCKFILE"
답변
sem
GNU parallel
도구의 일부로 제공되는 것은 당신이 찾고있는 것일 수 있습니다.
sem [--fg] [--id <id>] [--semaphoretimeout <secs>] [-j <num>] [--wait] command
에서처럼 :
sem --id my_semaphore --fg "echo 1 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 2 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 3 ; date ; sleep 3" &
출력 :
1
Thu 10 Nov 00:26:21 UTC 2016
2
Thu 10 Nov 00:26:24 UTC 2016
3
Thu 10 Nov 00:26:28 UTC 2016
주문이 보장되지는 않습니다. 또한 출력은 끝날 때까지 표시되지 않습니다 (자극!). 그러나 그럼에도 불구하고 잠금 파일과 재시도 및 정리에 대해 걱정하지 않고 동시 실행을 방지하는 가장 간결한 방법입니다.
답변
사용 dtach
합니다.
$ dtach -n /tmp/socket long_running_task ; echo $?
0
$ dtach -n /tmp/socket long_running_task ; echo $?
dtach: /tmp/socket: Address already in use
1