経緯
crontabに仕込んだシェルスクリプトの多重起動防止のロジックを入れたところ、うまく動作しなくて原因がわかって改良したのでその覚書です。
原因がわかった時に自分の無知さに打ちひしがれましたが、これで一つ賢くなったと前向きに考えたいと思います\(^o^)/
改修前
スクリプト
多重起動防止ロジック
if [ $$ -ne `pgrep -fo "$0"` ]; then
exit 1
fi
解説
| コマンド | 説明 |
|---|---|
| $$ | 自分自身のプロセスID |
| pgrep | パターンにマッチするプロセスのプロセスIDを返す |
| -f | パターンをコマンドライン全体(パスや引数を含める)と照合する |
| -o | パターンにマッチする一番古いプロセスのプロセスIDを返す |
| $0 | 自分自身のスクリプト名(パス名) |
$$(現在起動しているスクリプトのプロセス番号)とpgrep -fo "$0"(スクリプトの一番古いプロセス番号)が一致しなかったら既に起動していると見なし、exitで抜けるという処理。
何が悪かったか
cronからプロセスを起動させる場合、cronから子プロセスとして起動するため、多重起動の処理が誤判定をしてしまい、スクリプトが実行されていなかった。
改修後
スクリプト
多重起動防止ロジック
lock=test_file.lock
exec 44 > $lock
flock --nonblock 44 || exit 0
解説
lock=test_file.lock
- lockファイルの定義
exec 44 > $lock
-
$lockファイルを任意のファイルディスクリプタ44で開く
flock --nonblock 44 || exit 0
- システムコール
flockにてファイルディスクリプタ44で開いているファイルをロックできれば、スクリプト処理を実施し、できなければexitで強制終了させる