10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DjangoAdvent Calendar 2019

Day 14

cronpi × Django Custom Commandで気楽にcronジョブ管理

Last updated at Posted at 2019-12-14

この記事は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点で動作確認を行う。

  1. cronpi設定用Commandとログ出力用Commandを作成する
  2. cronpi設定用Commandを実行する1
  3. crontabで実行されたCommandのログを確認する

実践!

1.cronpi設定用Commandとログ出力用Commandを作成する

cronpi設定用Command

いい感じですね、よく順序忘れてしまう*記法使わなくて済むので。

init_scheduler.py
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
hogehoge.py
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!')
uhouho.py
# import  省略
class Command(BaseCommand):
    def handle(self, *args, **options):
        logger = logging.getLogger('command')
        logger.info('uhouho!')
foo.py
# import  省略
class Command(BaseCommand):
    def handle(self, *args, **options):
        logger = logging.getLogger('command')
        logger.info('foo!bar!')
settings.pyよりloggingのみ抜粋2
settings.py
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を使うと次の利点がありそう。

  1. Django内で設定が完結するのでコード管理が楽
  2. cronの日付記法を忘れても良さそう
  3. crontab -rの恐怖を味わう機会が減ってハッピー

反省

締め切りギリギリですね、以降はもう少し早めに着手したい。
あと結構勢いで書いてたりするので多少アラがあるかもしれません。その際はご指摘ください。

課題・懸念点

  1. cronpiにcron設定削除処理がないので、都度都度消す必要がある。もちろん、毎度まっさらな環境にプロジェクトを配置できるのであれば気にしなくて良さそう
  2. cronpi.get_job_list()の出力結果はcronの日付記法なのでなんだかんだググる必要はあるかもしれない
  3. 実はDjagno向けのcronパッケージが存在することをこの記事を書いているときに知った、比較検討が必須
  1. 本番導入時はデプロイ時に何かしらで起動させてあげれば良い気がする

  2. cronからの起動時は、logging.FileHandlerにわたすfilenameは絶対パスじゃなきゃいけないの知らなくてちょっとハマった。参考サイト 3

  3. 実はこの参考サイトでDjango向けのcronパッケージがあることを知った。

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?