この記事はDjango Advent Calendar 2019 の14日目の記事です。
初投稿だったりします。お手柔らかにお願いします。
はじめに
毎日ワクワクしながら本番環境でやらかしちゃった人 Advent Calendar 2019を読んでいるのですが、
crontabで失敗している人が散見されているようですね。
私も日頃crontabには思うところ(毎度ヒヤヒヤしながらcrontab -e
打ったり、毎度日付の設定方法を忘れてググったり、地味に設定ファイルの管理めんどくさい)があり、なにか良い対策ないのかよーと思って探してみました。
ありました、cronpi
です。
human readableな日付記法とpythonファイルでcronジョブ管理ができるパッケージらしいです。ありがたい...詳しくはこちら
見つけたcronpiと普段お仕事で使うDjangoCustomCommandを組み合わせたら少しは楽になるのではと思い、執筆しました。
概要
やりたいこと
cronpiとDjango Custom Command(以降、Commandとする)を組み合わせて使用することで、
はじめにで長々と書いた「思うところ」からいくらか開放されることをご紹介したい。
なお、今回はこんなやり方あるかもってことを紹介したいだけなので、細かいProjectの設定等や実行環境については一切言及しない。
手順
以下の3点で動作確認を行う。
- cronpi設定用Commandとログ出力用Commandを作成する
- cronpi設定用Commandを実行する1
- crontabで実行されたCommandのログを確認する
実践!
1.cronpi設定用Commandとログ出力用Commandを作成する
cronpi設定用Command
いい感じですね、よく順序忘れてしまう*記法使わなくて済むので。
from pathlib import Path
from django.conf import settings
from django.core.management.base import BaseCommand
import cronpi
class Command(BaseCommand):
def handle(self, *args, **options):
python = '/usr/local/bin/python3.7'
manage_path = Path(settings.BASE_DIR) / 'manage.py'
# 2019と書いてあるが、毎年12月14日23:40に実行される。
cronpi.run_by_date(f"{python} {manage_path} hogehoge", isOverwrite=True).on('2019-12-14 23:40')
# 毎週土曜日、月曜日の23:40に実行される
cronpi.run_every_week(f"{python} {manage_path} uhouho", isOverwrite=True).on(['sat', 'mon'], time='23:40')
# 毎月14日の23:40に実行される
cronpi.run_every_month(f"{python} {manage_path} foo", isOverwrite=True).on(14, time='23:40')
# 登録されているjob一覧を取得してくれるらしい。
current = cronpi.get_job_list()
self.stdout.write('\n'.join(current))
ログ出力用Command
from django.core.management.base import BaseCommand
import logging
class Command(BaseCommand):
def handle(self, *args, **options):
logger = logging.getLogger('command')
logger.info('hoge!hoge!')
# import 省略
class Command(BaseCommand):
def handle(self, *args, **options):
logger = logging.getLogger('command')
logger.info('uhouho!')
# import 省略
class Command(BaseCommand):
def handle(self, *args, **options):
logger = logging.getLogger('command')
logger.info('foo!bar!')
settings.pyよりloggingのみ抜粋2
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(levelname)s : %(asctime)s : %(message)s',
}
},
'handlers': {
'file_handler': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': BASE_DIR + '/myLog.log', # cronから実行する際は絶対パスでなければならない
'formatter': 'simple'
},
},
'loggers': {
'command': {
'handlers': ['file_handler'],
'level': 'INFO',
},
}
}
2.cronpi設定用Commandを実行する
(my_env) ~/PycharmProjects/django3/mysite $ python manage.py init_schedule
10 23 14 12 * /usr/local/bin/python3.7 /Users/gorilla/PycharmProjects/django3/mysite/manage.py hogehoge
10 23 * * 6,1 /usr/local/bin/python3.7 /Users/gorilla/PycharmProjects/django3/mysite/manage.py uhouho
10 23 14 * * /usr/local/bin/python3.7 /Users/gorilla/PycharmProjects/django3/mysite/manage.py foo
3.crontabで実行されたCommandのログを確認する
動いてる!
INFO : 2019-12-14 23:40:01,215 : hoge!hoge!
INFO : 2019-12-14 23:40:01,215 : banana!
INFO : 2019-12-14 23:40:01,215 : foobar!
最後に
まとめ
cronpiを使うと次の利点がありそう。
- Django内で設定が完結するのでコード管理が楽
- cronの日付記法を忘れても良さそう
-
crontab -r
の恐怖を味わう機会が減ってハッピー
反省
締め切りギリギリですね、以降はもう少し早めに着手したい。
あと結構勢いで書いてたりするので多少アラがあるかもしれません。その際はご指摘ください。
課題・懸念点
- cronpiにcron設定削除処理がないので、都度都度消す必要がある。もちろん、毎度まっさらな環境にプロジェクトを配置できるのであれば気にしなくて良さそう
- cronpi.get_job_list()の出力結果はcronの日付記法なのでなんだかんだググる必要はあるかもしれない
- 実はDjagno向けのcronパッケージが存在することをこの記事を書いているときに知った、比較検討が必須