参考情報:シェルスクリプトでの排他処理
概要
2重起動をbashで抑止しようとした場合、lockファイルを作成するだけだと、
不慮のプロセス停止になった場合、lockファイルが削除されずに、
手でlockファイルを削除しないと永遠に起動出来ないことになってしまう。
それではちょっと不便なので、なんとか本当に2重起動しようとしているかどうか、
pid(Process ID)も組み合わせて、判断するようにしてみた。
以下の条件を完全に満たす場合、2重起動とする。
-
自ファイル名.pidファイル が存在している
→lockファイル方式 -
ファイルの1行目に書かれているプロセスが存在した場合
(/proc/ ディレクトリにpidのディレクトリが存在する)
→不慮の事故(kill -9)等によりlockファイルが残っていた場合の自動リカバリ処理 -
自分と同じプロセス名を検索結果のpid一覧と.pidファイルのpidが一致する。
→プロセスの大量生成等により、別プロセスが該当のpidを使用しても対応可能
→検知漏れ、誤検知を防ぐ
検知漏れの例:bash ./command でも、 ./command でも検出できる
誤検知の例 :commandプロセスを探して、command.shを引っ掛けないように
また、trapコマンドも使って1関数の中に2重起動抑止に必要な処理を全部埋め込んだ。
というのを、CentOS の /etc/init.d/functions を参考にしながら作ってみました。
ソース
判定処理
# !/bin/bash
# 2重起動チェック
function checkDuplicate()
{
local RET=0
local base=${0##*/}
local pidfile="/tmp/${base}.pid"
while true; do
if ln -s $$ ${pidfile} 2> /dev/null
then
# 起動OK
RET=0 && break
else
p=$(ls -l ${pidfile} | sed 's@.* @@g')
if [ -z "${p//[0-9]/}" -a -d "/proc/$p" ]; then
local mypid=""
for mypid in $(pgrep -f ${base})
do
[ ${p} -eq ${mypid} ] && RET=1 && break
done;
fi
[ ${RET} -ne 0 ] && break
fi
rm -f ${pidfile}
done
# チェック結果を判定して、pidファイルを作成する。
# 正常終了、シグナルを検知するとpidファイルを削除する。
if [ ${RET} -eq 0 ]; then
trap "rm -f ${pidfile}; exit 0" EXIT
trap "rm -f ${pidfile}; exit 1" 1 2 3 15
fi
return ${RET}
}
使い方
# 2重起動チェック
checkDuplicate
if [ 0 -ne $? ]; then
# ここにエラー処理を書く
fi
2013/3/19 lockファイルのチェックと作成を1コマンドで
作成することにより、起動中はエラーだったけど
処理している間に起動OKになったりしないように
対応しました。