cron実行スクリプトの多重起動防止ワンライナー、これでええやん
ジョブの多重実行問題
よくこんな感じで1分おきにジョブを流したい場合があると思う。
1 |
* * * * * /path/to/your/cron_job.sh |
ところがこのcron_job.shが1分以内に処理が終わらない場合、1分後には同じスクリプトが2重で起動されてしまう。
これは良くないので、多重起動の防止策が必要ねというのがそもそもの課題。
多重実行防止方法
cron_job.shの内部ロジックとして、多重実行を防ぐ
ジョブのスクリプト内に、DBのstatusカラム(0:未実行, 1:実行中, 2:実行完了)を作成して、statusを参照することで多重起動防止する。
というような施策を行うことがあるが、これが機能しないとバグになるし、ジョブ起動の管理はスクリプト本体からは切り離したい。というかそもそも毎回そんな処理を書き足すのが面倒くさい。
cron_job.shプロセスの実行状況を確認して、多重実行を防ぐ
こういうケースではジョブの実行開始時にロックファイルを作成して、ロックファイルがあったら後追いのcronでは実行しちゃだめよーという方法がポピュラーらしいが、なんか面倒に感じる。
ということで、簡単な方法を求めていたら、pidofコマンドを使ってジョブの実行状況を確認する方法だとワンライナー的に書けて一番便利そう。これでええやん。
1 |
* * * * * /usr/sbin/pidof -x cron_job.sh >/dev/null || /path/to/your/cron_job.sh |
ワンライナーの説明
- 「||」の左辺がプロセスの実行状況確認、右辺が実際のスクリプト。
- pidofは-xオプションを付けないと、自作スクリプトなどのプロセスの存在を検出してくれない。
pidofはプロセスが1つ以上存在する場合は0以外のリターンコードを返す。- pidofはプロセスが少なくとも一つ存在する場合: 0, 存在しない場合: 1を返す
- 「||」は左辺が0意外なら右辺を実行する
一応テストしてみる
処理終了に1分以上(70秒)かかるスクリプトを作成した。
1 2 3 4 5 |
#!/bin/sh echo "-- pid:$$ start -- " sleep 70 echo "-- pid:$$ end --" |
多重実行防止「無し」で試す
これを1分おきのcronで定期実行し、ジョブの開始と終了をlogに保存する。
1 2 |
# for cron test * * * * * /root/tmp/crontest.sh >> /root/tmp/crontest.log |
多重実行防止があれば同じプロセスID(pid)のstart, endが交互に来るはず。
が、crontabに多重実行防止の処理を入れてないので結果は以下のようにあちゃーとなる。別プロセスIDのstartとstartが連続して続いていることから、思いっきり2重に起動している。
1 2 3 4 5 6 7 |
-- pid:35076 start -- -- pid:35166 start -- -- pid:35076 end -- -- pid:35256 start -- -- pid:35166 end -- -- pid:35348 start -- -- pid:35256 end -- |
多重実行防止「有り」で試す
ここで、例のcron多重起動防止ワンライナーを使ってみる。これでどーでしょー!!
一点注意なのはcron実行ユーザーの環境変数のせいか、pidofをcronで使うと、そんなコマンドは無いと怒られます。たぶんパスが通ってないようです。なので、crontabでpidofを使う際は、/usr/sbin/pidof
と絶対パスで指定してください。
1 2 |
# for cron test * * * * * /usr/sbin/pidof -x crontest.sh >/dev/null || /root/tmp/crontest.sh >> /root/tmp/crontest.log |
結果は素晴らしい!きちんと同じプロセスIDのstart, endが交互に来てます。多重実行が防止できていることがわかる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
-- pid:39786 start -- -- pid:39786 end -- -- pid:39974 start -- -- pid:39974 end -- -- pid:40155 start -- -- pid:40155 end -- -- pid:40340 start -- -- pid:40340 end -- -- pid:40520 start -- -- pid:40520 end -- -- pid:40700 start -- -- pid:40700 end -- -- pid:40897 start -- -- pid:40897 end -- -- pid:41086 start -- -- pid:41086 end -- -- pid:41273 start -- -- pid:41273 end -- -- pid:41453 start -- -- pid:41453 end -- -- pid:41636 start -- -- pid:41636 end -- |
簡単につかえて、これでええやん。( ´_ゝ`)ノ