Last Updated: February 25, 2016
·
843
· showaid

Locking Shell Script

스크립트가 중복되어서 실행 될 수 있는 경우 예상치 못한 문제들이 발생할 수 있다. 따라서 스크립트가 실행 되고 있는 경우 동일한 스크립트가 실행되지 않도록 하는 장치를 마련해야 하는데, 이게 말처럼 쉬운일은 아니다.

이때 일반적으로 사용하는 것이 파일을 이용한 locking 인데, 일반적으로 touch등을 이용하여 파일을 만들고 이 파일을 lock으로 이용한다. 하지만 이러한 방법은 내부적으로 1. 파일이 있는지 체크를 하고, 2. 없는경우 파일을 생성하는 알고리즘을 쓴다. 보시다시피 이건 atomic이 아님!

이에 대한 대안으로 사용할 수 있는 것이 mkdir이다. mkdir은 파일을 생성하는 명령어와는 다르게 디렉터리 생성 시 디렉터리가 있으면 에러가 발생하게 된다. 이를 이용해서 atomic operation을 보장한다는 것인데, 실제 사용 예제를 보면 어려운 내용은 아니다.

# locking example -- CORRECT
# Bourne
lockdir=/tmp/myscript.lock
if mkdir "$lockdir"
then    # directory did not exist, but was created successfully
    echo >&2 "successfully acquired lock: $lockdir"
    # continue script
else
    echo >&2 "cannot acquire lock, giving up on $lockdir"
    exit 0
fi

위와 같이 mkdir 사용을 통해서 kernel level의 원자성을 보장할 수 있다.

스크립트의 수행이 종료되었을 때 자동으로 lock을 삭제하는 방법까지 포함한 예제는 다음과 같다.

# POSIX (maybe Bourne?)
lockdir=/tmp/myscript.lock
if mkdir "$lockdir"
then
    echo >&2 "successfully acquired lock"

    # Remove lockdir when the script finishes, or when it receives a signal
    trap 'rm -rf "$lockdir"' 0    # remove directory when script finishes

    # Optionally create temporary files in this directory, because
    # they will be removed automatically:
    tmpfile=$lockdir/filelist

else
    echo >&2 "cannot acquire lock, giving up on $lockdir"
    exit 0
fi

여기서 좀 더 나가면 쉘스크립트가 정상적으로 종료되지 않은 경우(ex. kill -9)에 발생할 수 있는 stale lock 처리까지 생각할 수 있을 텐데, 일단 이정도 만으로도 일반적인 동시성 문제는 상당부분 해소할 수 있을 것이라 생각한다.

참조

Stale lock 과 관련된 처리가 필요하다면...