失敗例「cronで実行すると常に二重起動と判定される」
この方法により二重起動をチェックするシェルスクリプトを作成し、cronで実行したところ、常に二重起動と判定されて処理が中断する、というハメに陥りました。もちろん、二重起動は誤判定です。
プロセスIDを調べたところ、
echo $$ # => 6943
echo `pgrep -fo $0` # => 6942
と、自分自身のプロセスID
とパターンにマッチする一番古いプロセスのプロセスID
が一致していません。
それぞれのプロセスIDに対応するプロセスを調べると、
6942 ? Ss 0:00 /bin/sh -c /home/tetsuyai/bin/create_summaries.bash 2>> /home/tetsuyai/create_summaries.error.log
6943 ? S 0:00 /bin/bash /home/tetsuyai/bin/create_summaries.bash
となっていました。6942はcronによって実行されたプロセス、6943はそこから実行された子プロセスです。
本命の処理は6943で実行されています。二重起動のチェックもそこで行われるので、自分自身のプロセスIDは6943になります。一方、pgrepに-fオプションを渡しているため、/home/tetsuyai/bin/create_summaries.bash
にマッチする一番古いプロセスは親プロセスである6942になります。これが誤判定の原因でした。
ひとつの解決策として、cronで実行するときはpgrepに-fオプションを渡さない、という方法があります。その場合、pgrepはプロセス名のみと照合するため、6942はsh
、6943はcreate_summaries.bash
となり、`basename $0`で取り出したファイル名とマッチするのは6943になります。
_pname=`basename $0`
[ $$ != `pgrep -fo $_pname` ] && { echo 'Cannot run multiple instance.' >&2; exit 9; }
この方法は比較的簡単に誤判定を回避できますが、パスも引数も無視してプロセス名でのみ比較するため、それはそれで都合が悪い、というケースもあるでしょう。その場合、次の「ロックファイルを使う方法」が適しているかもしれません。