cron力をつけよう!全てのcrontab入門者に贈る9個のテクニック

はじめに

crontab使いこなしてますか?

crontabの設定を適当に書いて、動いてるからこれでいいやと思っていたりしませんか?

1週間前までの私は、そんな状態でした。
$ crontab -l
0   9 * * * /bin/bash /home/dqneo/bin/hoge.sh > /dev/null 2>&1
0  10 * * * /bin/bash /home/dqneo/bin/fuga.sh > /dev/null 2>&1
0  11 * * * /bin/bash /home/dqneo/bin/piyo.sh > /dev/null 2>&1
0  17 * * * /bin/bash /home/dqneo/bin/piyo.sh > /dev/null 2>&1
このような設定であったために、「ログが残らない」「障害が起こっても気づかない」など様々な問題を抱えていました。

これではいかんと一念発起して勉強しなおしたら、実に驚くほどたくさんの改善の余地がありました。
そこで私が学んだノウハウをここに紹介します。

これであなたもcron初心者を卒業!!
ちょっと工夫するだけで、圧倒的に安全にそして楽に!

なお、時間設定方法や書式についてはここでは解説しません。
拙作「くろんメーカ」をお使いください。

くろんメーカ - crontab用のコマンドを自動で生成します。 そのままコピペしてお使いください。

crontab -e で直接編集しない

有名な話ですが、crontab -r とやってしまうと全てが一瞬で消え去ります。
まさにバルス!

間違えて crontab -r してしまい、crontab をふっとばしてしまった。つか、隣同士にある -e と -r で編集と削除とか、酷いよ><。。。
crontab -r を安全にする - antipop

必ずローカルファイルに設定を書いたうえで、それを反映させるようにしましょう。
$ crontab -l > ~/crontab # 現在の設定をバックアップ
$ vi ~/crontab           # ローカルファイルを編集
$ crontab < ~/crontab    # ローカルファイルを反映する

crontab設定をバージョン管理する

誰がいつ何をいじったか履歴が残るように、svnやgitなどのバージョン管理システムに登録しておきましょう。

トラブルが起こったときに、このログを見れば、直近のcrontab設定変更がどのようなものであったのかすぐに確認することができます。

恐怖のcrontab -r. 設定ファイルはレポジトリ管理せよ - Slow Dance

MAILTOを必ず設定する

MAILTOを設定しないままだと、サーバ内のユーザローカルのmailboxに入ってしまいます。
一応mailコマンドで見れますがこれだと不便なので、専用のアラート受信用メールアカウント(会社や部署のMLなど)を用意してcrontabの冒頭で設定しましょう。
MAILTO="alert@yourdomain.com"

標準出力は捨てない (> /dev/null してはダメ)

バッチのログは非常に重要です。
command > /dev/null などしてしまうと、イスを投げられます 何かが起こったときに調査のしようがなくなります。
ログは必ずどこかに出力するようにしましょう。

一番簡単なのは、専用ログファイルに追記してしまうことです。
command >>  /path/to/logfile
(ただしこの場合はログファイルが肥大化してディスクフルにならないように、ローテーションの仕組みを別途作っておきましょう。)

ログ管理についてはこちらの記事が参考になります。

cron で > /dev/null して椅子を投げられないための3つの方法 - 酒日記 はてな支店

エラーメッセージは標準エラー出力に吐く

たまに標準出力にエラーメッセージを吐いてしまっているケース(注1)を見かけますが、これではエラーと正常の区別がつかないので意味がないです。
障害発見が遅れてしまいます。
悪い例
echo "error message"
exit 1
良い例
スクリプト内でエラーが起きたときのエラーメッセージは、必ず標準エラ―出力に吐きましょう。
echo "error message" 1>&2
または
echo "error message" > /dev/stderr

exit 1
(注1:エラそうに言ってますが、1週間前までの私のことです)

コマンド重複をまとめる

朝と夕の1日2回実行するような場合に、たまに2行書いてる人がいます。(注2)
悪い例
0  11 * * * /bin/bash /home/dqneo/bin/piyo.sh 
0  17 * * * /bin/bash /home/dqneo/bin/piyo.sh
あたり前ですが1行にまとめましょう。
良い例
0  11,17 * * * /bin/bash /home/dqneo/bin/piyo.sh
(注2:エラそうに言ってますが、1週間前までの私のことです)

パス名の重複をまとめる

下記のようなパス名の重複も気になります。
悪い例
0   9 * * * /bin/bash /home/dqneo/bin/hoge.sh >> /home/dqneo/logs/hoge.log
0  10 * * * /bin/bash /home/dqneo/bin/fuga.sh >> /home/dqneo/logs/fuga.log
これは環境変数を使ってまとめるとすっきりします。
良い例
BIN_DIR="/home/dqneo/bin"
LOG_DIR="/home/dqneo/logs"

0   9 * * * /bin/bash $BIN_DIR/hoge.sh >> $LOG_DIR/hoge.log
0  10 * * * /bin/bash $BIN_DIR/fuga.sh >> $LOG_DIR/fuga.log
※ LOG_DIR="$HOME/logs" のように右辺で変数を使うことは残念ながらできませんのでご注意。
crontabで環境変数を使う際に知っておきたいたった1つのこと - (゚∀゚)o彡 sasata299's blog

実行時間を0分きっかりにしない

素人は「何時0分」に起動する設定を書いてしまいがちです。
しかし例えば毎時0分に起動するバッチと、10時0分に実行するバッチが重なると、サーバに不要な負荷をかけてしまいます。
悪い例
0   * * * * /bin/bash $BIN_DIR/hoge.sh >> $LOG_DIR/hoge.log
0  10 * * * /bin/bash $BIN_DIR/fuga.sh >> $LOG_DIR/fuga.log
気休め程度ですが、「何時0分」とはせずに、「何時5分」とか「何時10分」とか微妙にずらしておきましょう。
良い例
5   *  * * * /bin/bash $BIN_DIR/hoge.sh >> $LOG_DIR/hoge.log
15  10 * * * /bin/bash $BIN_DIR/fuga.sh >> $LOG_DIR/fuga.log

コマンドの重複起動を防止する

「1時間に1回」のバッチは、「1時間に1本」しか走らないと思い込んでいませんか?
それは甘いです。

もしサーバの負荷上昇や処理量増大などが原因でバッチ処理が1時間以上かかってしまった場合、1個目のプロセスが終わらないうちに2個目のプロセスが起動してしまいます。

バッチが重複起動してしまうと、思わぬ事故を引き起こします。
重複起動の防止処理を入れておきましょう。

多重起動を防ぐシェルスクリプト - zenpouの日記

まとめ

いかがでしたか?
cronは簡単そうに見えて実に奥が深いですね。

素敵なcronライフをエンジョイしてくださいね!!

もっと良いやり方があればTwitterやはてブでご指摘いただけると幸いです。
カテゴリ:

人気記事