Cronが正しく動いていない気がする…PythonとかSeleniumとか
どうも、本格的に開発中のサービスを公開しまして、必要になってきたのがcronです。
cronは時間を指定して自動的にジョブを実行してくれる素晴らしい機能です。クローリングプログラムとかSNSへの投稿BOTなんかでよく使われているのではないでしょうか。
今回はそんなcronがなんだか正しく動作していない場面に遭遇したので、試行錯誤の結果得られた対策方法をチェックリスト兼備忘録的にまとめておこうと思います。ちなみに作業はCentOS上で、crontabコマンドを用いることで設定しています。
OS : CentOS 6.8
Contents
1. crontabの基本的な記述
さて、まずは基本的な使い方をまとめておこうと思います。はじめに、cronを動かすための設定ファイルを記述します。設定ファルは、以下のコマンドを使うことでエディタが起動するので、そこで編集することができます。
1 |
$ crontab -u [username] -e |
おそらくviやらvimやらが起動するところが論争を呼びそうですが、編集していきます。
基本的な記述は以下のとおりです。
1 2 3 4 5 6 7 8 9 10 11 |
分 時 日 月 曜 [command] 例1) 毎日1時にshファイルを実行 0 1 * * * ./xxx.sh 例2) 火曜日の毎時0分と30分にecho */30 * * * 2 echo 'HOGE' 0,30 * * * 2 echo 'HOGE' 例3) 毎日1時から3時にshファイルを実行 0 1-3 * * * /path/to/xxx.sh |
はじめ見た時はよくわかりませんでしたが、要は時間を指定して、あとはいつも通りのコマンドをくっつけるだけです。
2. チェック項目
では本記事の本題です。cronを設定したのに、なんだかちゃんと動いてないというときに自分がチェックした項目をまとめていきます。
crondはうごいているか?
まずは、超絶基本項目。そもそもcronのデーモンは動いているかです。とりあえず下記のようなコマンドでcrondの状態を確認してみてください。
1 |
$ service crond stutas |
これで動作中だったら大丈夫だと思います。ダメならstutasのところをstartにすれば良いのではないでしょうか。ディストリビューションによっては上記のコマンドじゃない場合があるのですが、それはご自身の環境によって置き換えてください。
そもそも、単体では動くのか?
またまた基本項目ですが、記述しているコマンドは単体では動くのかを一応確認してみてください。もしかしたら、コマンドやオプションの記述ミスをしているかもしれません。お恥ずかしい話、自分の動かなかった原因の一つはこれでした。実行するコマンドをpythonコマンドからshスクリプトにした際にpythonコマンドを消し忘れていました。
絶対パスに変えてみる
これも単純な項目ですが、呼び出すファイルやコマンドなんかは絶対パス(フルパス)で書くほうが良いとのことです。
実行権限があるかを確認する
これも単純(以下略。
cronを実行するユーザにおいて、コマンドを実行する権限があるかを一応確認してみてください。
エラーログファイルをチェック
基本的な項目を確認してもダメなら、エラーログをチェックしてみましょう。エラーファイルは”/var/log/cron”です。これをtailコマンドなんかで開いて確認してみてください。今回は何も該当していなかったので何も書けませんが、エラーが出力されていれば参考にはなるかと思います。
一応注意なのですが、ここでエラーとして出力されるのはcronのエラーなので、実行するコマンド内で発生したエラーについてはここには出力されないようです。もし実行するコマンド内のエラーを確認したい場合は以下のように実行するコマンドの出力先を指定してあげれば、エラー文を出力することができます。
1 |
* * * * * [実行するコマンド] 1 > /path/to/log1.out 2 > /path/to/log2.out |
ちょっとややこしい記述になっていますが、標準出力とエラー出力の両方をログに出力するために2つのファイルを生成しています。
3. 特定のコマンドが動かない
さて、ここまでやっても自分の環境ではうまく動作してくれませんでした。今回遭遇した場合だと、主にpythonで書いたSelenium(+PhantomJS)を使ってブラウザを操作する感じのプログラムを実行するコマンドが動かないものの、他のテスト用のプログラムは動くという状況でした。
もちろん上記で示した項目はすでに確認しましたし、プログラム単体なら動きます。というわけで、今回はこれの原因を探しました。
さて、現状の確認です。まず、cronの設定ファイルに先ほどのエラー文出力の記述を追加します。これで、エラー文がlog2.outに出力されるようになりました。これを確認すると、SeleniumのモジュールからPhantomJSのインスタンスを生成する際にPhantomJS本体を見つけることができずにエラーになっているようでした。
つまり何が言いたいかというと、普通にコマンドを実行した時と、cronを使って実行した時とでは、PATHが異なっているかもしれないということです。もうひとつ気になるのは、通常時に実行しているコマンドとcron内で実行されるコマンドが別物なのではないかということです。
コマンドの実体位置を調べる
では、特定のコマンド(今回は”python”)がどこに存在しているかを確認してみます。確認するには以下のコマンドです。
1 2 |
$ # which [command] $ which python |
このコマンドを実行すると指定したコマンドの実体がどこにあるかを確認することができます。あとは、cron内でも同じことをしてみます。
1 |
* * * * * which [command] > test.out 2 > itiou.out |
この設定で出てきた実体と先ほどのものを比較して場所が異なっていたら、そこが正しく動作しない原因かもしれません。もし違っていたら、正しく動く方の絶対パスを設定に書き込めば正しく動くかもしれません。
cron設定内でPATHを通す
今回の環境では、上記の対策だけでは不十分でした。というのもどうやらPATHも通さないと行けないみたいでした。というわけで、普段のPATHをそのままcronの設定に織り込んでしまおうと思います。ちなみに、この方法は無駄が多い気がしますが、お手軽に解決できるのでお試しにはもって来いです。
まずは、ECHOコマンドを用いて現在のPATH状況を確認してみます。
1 |
$ echo $PATH |
これで現在設定されているPATHが出力されます。あとは出力されたものをcronの設定に書き込めば大丈夫です。とういわけで、”crontab -e”で設定ファイルを読みだして、以下の項目を書き込みます。
1 2 3 4 5 |
PATH=[ECHOしたPATHの内容] LANG=ja_JP.utf-8 # 以下実行するコマンドの設定 * * * * * /path/to/python /path/to/python_code.py |
自分の環境では、これで正しく動作するようになりました。
ちなみに上記の例ではPATHの他にも、おまけで文字コードの設定なんかも行いましたが、今回はあまり活躍していないようでした。
コーディングで分からないことがあれば
プログラミングや環境構築で分からないことがあったら『teratail』というエンジニア特化型のQ&Aサービスがオススメです。自分もどうしても分からないことがあったら、時々質問しにいきますが、かなりニッチな質問にも意外と早く回答がつくのでとても頼もしいです。という宣伝でした。
おわりに
さて、今回は、cronの設定と動作しなかった時のチェックリスト的な感じでまとめてきましたが、正直玄人さんには基本の「き」のものばっかりだったと思います。しかし、何事も基本が大事だろと言い張りつつ今回はこの辺で終わりたいと思います。
ディスカッション
ピンバック & トラックバック一覧
[…] http://foolean.net/p/781 […]