App::RunCron has been released!
https://metacpan.org/module/App::RunCron
tl;dr
cronlogより可搬性は落ちてシンプルさには欠けるけど、もうちょっと機能拡張してプラガブルな設定ができるruncronてやつを作った。コマンドの成功/失敗に応じて通知方法を変更できるようになっている。
本題
cronで困るのは、ログだったり通知であったりをどうするかというところです。
で基本的にどうするか、というところは@fujiwara組長の、 「cron で > /dev/null して椅子を投げられないための3つの方法」 に書いてあります。まとめると以下になります。
- 全部メールで投げる(> /dev/null は論外)
- 標準出力、エラー出力をまとめて、何らかのloggerに投げる(syslogがお手軽)
- 場合によってはcronlogで選別して失敗した時のみ通知する
最近は以下のように、syslogを使わずにfluentdに投げたりしているプロジェクトもあります。
LOGGER="/usr/local/bin/fluent-agent-lite -f msg"
* * * * * /path/to/command 2>&1 | $LOGGER cron.command - fluentd-srv localhost
ただ、結局まとめて投げてしまうとノイズが多くなるし、ログの受け側で正しく選別したりとか、スクリプト側でちゃんとエラー時の処理を書いたりするのがめんどくさい。ログの受け側でコマンドの終了コードを知るのが難しいところも悩ましいところですね。
そこで、先程も少し触れましたが、安心と信頼のkazuho wareであるcronlogというものがあるわけです。
これは、コマンドの終了コードに応じて処理が分けられるようになっています。コマンド成功時は何も出力しないし、失敗時は標準出力に出力されるようになっているという具合です。--logfile で別途ログを残しておくことも可能です。一枚岩でPerlの標準モジュールだけで動くので、非常に可搬性に優れていて、完成されています。
ただ、これは元々、監視用途に寄っているユースケースなので、もうちょっと細かい制御をアプリケーションでやろうとすると、もう少し機能が欲しくなってきます。
具体的には以下のような感じです。
- コマンド成功時、失敗時の通知処理を標準出力以外も指定したい
- --log-fileが '%Y%m%d.log' とか指定できるようになっていて欲しい
そこで、それらを解決するべく、App::RunCronというものを作りました。かなりcronlogのコピペです。
% cpanm -v App::RunCron
で、runcron
というコマンドがインストールされます。runcron
は標準では、cronlogとほとんど同じ動きをしますが、引数を指定することにより、通知の振る舞いを変更することが可能です。一番簡単なのは、-c
で設定ファイルを指定するか、実行ディレクトリに'runcron.yml'というファイルをおいておくことです。以下の様な具合です。
timestamp: 1
reporter:
- Stdout
- "+MyApp::Reporter::IRC"
error_reporter:
- Stdout
- "+MyApp::Reporter::IRC"
- "+MyApp::Reporter::Alert"
こうすれば、コマンドが失敗した場合に、アラートを飛ばすことができるようになります。あとは以下のようにcrontabに設定するだけです。
LOGGER="/usr/local/bin/fluent-agent-lite -f msg"
LAUNCH="/home/app/project/env.sh runcron -- "
* * * * * $LAUNCH command ... 2>&1 | $LOGGER cron.command - fluentd-srv localhost
env.shはよくあるラッパーシェルで、これを噛ませると、環境変数を適宜設定した後、プロジェクトディレクトリにcdしてくれるようなやつです。
runcron --logfile=log/\%Y-\%m-%d.log
とかも可能ですが、crontab内では、%にエスケープが必要なことにご注意下さい。
Reporterモジュールの作り方とかはドキュメント読んで下さい。非常に簡単です。
runcron
コマンドを使わずとも、App::RunCronを直接使うことで独自のラッパーコマンドも簡単にお作りいただけます。
ロック機構入れようかと一瞬思ったけど、setlock使えばいいよねってことで却下しました。
お試し下さい。