決まった時間に実行するなどは、基本的に自動化されるが「一度しか実行されないもの」または「何度も実行するが、いつ実行されるか決まっていない」場合は自動化したくてもしようがない。なので、手動で実行する。
一度しか実行しないバッチは、「データベースのカラムを追加、変更したのでデータを追加/修正したい」など。
何度も実行するバッチは、「問題が発生した場合、ユーザーに対する補填(いわゆる詫び石付与)」などが考えられる。
そして、この2つのバッチの対象者は、多い場合と少ない場合がある。
実行のオプションを付けない限り、dryrun
人間なのでついうっかり本番で動かしちゃったとかあるので、それを防止する。
動かそうと思って動かすのと動かすつもりがなくて動くのは全然違う。
スクリプトファイルにベタでコードを書かない
例えばPerlだと.plにコード書くのはあまりしなくて、.pmに分けたりする。
そうすることで、テストのしやすさを向上させて、テストを書く障壁を低くする。
rakeタスクでもテストは書けるけど、moduleにしたほうがサクサク書けるよねというイメージ。
http://robots.thoughtbot.com/test-rake-tasks-like-a-boss
tmux上で実行する
別にtmuxでなくてもよくて、sshしてバッチ動かしたけどコネクションが切れてて途中で止まってましたとか死ねる。マジで
他にはscreen, nohupとかです
途中で止めない
実行してる途中で止めるとめんどいので、完走させてから考えるとよいです。
考えるためには、なんでコケたのか理解する必要があり、以下に書いた「エラーのログをファイルに取る」「変更のログをファイルに取る」をする必要があります。
エラーのログをファイルに取る
エラーが起きたらログを取ります。
printして満足するのではなくて、ちゃんと後から参照出来るようにファイルなりなんなりに落とし込みます。
fluentdに投げてアレコレするでも良いと思います。
変更のログをファイルに取る
エラーが起きずとも変更が起きたログを取ります。
変更のログは、前に書いたカスタマーサポートで活用出来る、行動ログ - パルカワ2と同じような感じで書くと良いとおもいます。
実行完了したら通知する
実行したら通知するようにしておきます。
growlとかそんなめんどいことはしなくて、IRCに通知します。
それでバッチが終わったら、エラーがないかなど確認します。
普通、通知系のメソッドなりがプロジェクトにあると思う。
MyApp::Notify::IRC->finished_batch_script;
みたいな感じでやると決まった文言が投稿されるという風にしておくと、IRCでハイライトしやすいのでオススメです。
あと実行結果をnopasteに貼って、そのURLをIRCに通知するとかしたことあるけど、実行結果がめちゃくちゃ大きくなってnopasteが悲鳴をあげるみたいな事あるので注意が必要です。
実行条件の洗い出し
- この時間以外で動いてほしくない
- 2回実行してほしくない
動いてほしくない状態というはわりかしあるので、それを防止する。
一気に全ユーザーを取得しない
ユーザーが50万人にいるサービスで、ユーザー全部を取ってきて、DBICやらActiceRecordのインスタンスを作ると死ぬのは容易に想像できる。
ActiveRecordには、find_in_batchesというのがあって、まあなんかよしなにしてくれるらしいのでそれ使いましょう。
追記
バッチ書くときは、「二回以上動かないようにする」or「二回以上動いても大丈夫なようにする」ってのと「途中で止まっても再実行すれば動くようにする」みたいなのも気をつけてた。
— songmu (@songmu) 2014, 10月 3
大事です
まとめ
そんな感じで気をつけることがたくさんあってバッチはだるいので極力書きたくない。こういう風にまとめても完璧ではない。なので、仕事しないのが一番いいと思いました。