Django のコマンドを作って定期的に実行する

なんてことはないが、ちょっとハマったのでメモ

流れ

  • Django の python manage.py some_command をつくる
  • crontab に登録する

それだけなんだけど、復習も込めて

Django でカスタムコマンドをつくる

単純なスクリプトならそのまま Python のスクリプトとしてつかえばいいとおもうけど、 Django のコマンドであること、またそれらのモデルとかと連携したり、まああと意味合い的にそっちにもたせたいとかあるとき、コマンドを自作できる。
日本語 1.0::アクションを自作する — Django v1.0 documentation
英語 1.5::Writing custom django-admin commands | Django documentation | Django
英語の最新版のほうがわかりやすい。

階層をつくる

リポジトリ/プロジェクト/アプリ/ とツリー構造があるとき、INSTALLED_APPS に通っているパスで management/commands をつくる。python なので __init__.py も忘れずに。

BaseCommand クラスを継承したクラスをつくる

例だと class Command(BaseCommand) としてつくってる。クラス変数にオプションやらなんやらを設定できる。引数は optparse ベースで現状 python 2.7 だから argparse なんじゃないのとおもったけど、PyPi にはそれっぽいライブラリをつくってくれている人はいる。

実際の処理をかく

自分の場合は def handle(self, *args, **options) は main と同じような扱いにして、あとは関数に分けた。logger とかそういうバッチ処理系のなんかはよしなにした。

動かす

ファイル名が実行コマンドになっている(クラス名ではない) ので python manage.py some_command で実行できる

pyhton manage.py some_command

crontab で動かす

定期的に実行するなら crontab はまあつかう。で、登録する。それはいいが、2つハマった。

実行ユーザーの登録

実運営的にどうするかはわからないけど、実行ユーザーを管理したい場合は crontab -u user -e で登録できる。だけど Ubuntu だと sudo する必用があったっぽくて、root 権限でしか動かせないかと思ってた。そんなことはなかった。

sudo crontab -u atas -e

でよい

virtualenv 環境

普段 Python 関係の開発だと virtualenv(pyvenv) は必須だと思うけど、シェルから簡単に叩ける virtualenvwrapper を使っていた。でも、cron の登録では workon など virtualenvwrapper のコマンドは叩けないよね、ってところで少しハマってた。なので直接 virtualenv を activate すればよい

. ~/.virtualenv/dev/bin/activate

つなげる

こうなる

# m, h, d, w, m, command
* * * * * . /home/atas/.virtualenv/dev/bin/activate && cd /path/to/porject && python mamage.py some_command

もうちょっとちゃんとやるならシェルスクリプトにして

#!/bin/bash
export DJANGO_SETTINGS_MODULE=mysite.settings
. /path/to/virtualenv/dev/bin/activate
cd /path/to/src
python manage.py some_command

のほうがいいかもしれない

トラブルシューティング

Django のカスタムコマンドはつくれている前提で crontab での実行がどうなってるかがみえなかった

  • 登録っぽいことをかく
  • ログは /var/log/syslog に出るらしい
  • crontab の設定自体は /var/spool/crontab/... にあるらしい(が、実ファイルを直接触ることは基本しないらしい)
  • tmux でペインを分けてログを監視する tail -f /var/log/syslog
    • ちなみに less で表示して shift f でも同じ事できるけど、圧倒的に普段は tail -f のほうがいい感じだった
  • logger も動かしているのでそのファイルの状態も tail -f some.log してみる
  • VM で開発しているのでたぶん大丈夫だけど時刻設定は date コマンドで確認する。1分を待つのが長い。
  • ユーザーやなんやらでうごかなかったけど、結局はよく考えたら virtualenv 環境で環境のパスを実行ユーザーが見れないと困るよね*1、というようなところで解決

まあ

ある

*1:この記事をかいたときPYTHONPATH だと思ってたけど違った