CeleryでDjangoアプリケーションにタスクキューを実装して、Herokuにデプロイした方法をまとめます。
Djangoアプリケーションにタスクキューを実装するのは今後も結構やるかなと思うので、他のアプリケーションでも使いやすい形で残そうと思います。
参考にしたのは、Celeryの公式様とか、CeleryをDjangoで動かすとか。
あとはHeroku公式のUsing Celery on Herokuあたりです。
ちなみにHerokuの公式ドキュメントに、HerokuはCeleryは完全にサポートしているよ!、と書かれてました。
頼もしい限りです。
やっぱり公式ドキュメントが充実していると開発がはかどりますね。
ドキュメントといえば、Redisのドキュメントもかなり充実してて助かりました。
django-redis documentation
ぜひ参考にしてみてください。
もくじ環境について
まず、タスクキューを導入したいDjangoアプリケーションはすでにHerokuにデプロイできる前提で進めていきます。
Djangoのアプリケーションの作成方法とかデプロイ方法に関しては、もうちょいノウハウがたまったら記事化しようと思ってます。
もしDjangoによるアプリケーション開発もこれから勉強するよ、って方はUdemyの動画教材がおすすめです。
僕も、この動画で始めました。
キャンペーン中なら1200円くらいなのでおすすめ。
プログラミング初心者でも安心、Python/Django入門講座
さて、環境に関しては以下の通りです。
Python:3.6.8
Django:2.2.4
OS:WSL2のUbuntu18.04
デプロイ環境:Heroku
インストールされているパッケージのバージョンに関しては、とりあえずrequirements.txtをまんま貼っておきます。
Redisのバージョンは3.3.8、Celeryは4.3.0でした。
たぶん2019年8月時点での最新バージョン。
Herokuってわりと最新のモジュールだと動かないイメージあったんですが、Celeryは問題ありませんでした。
さすが完全なサポートと豪語するだけありますね。
amqp==2.5.1 autopep8==1.4.4 billiard==3.6.1.0 celery==4.3.0 certifi==2019.6.16 chardet==3.0.4 defusedxml==0.6.0 dj-database-url==0.5.0 Django==2.2.4 django-allauth==0.39.1 django-celery-results==1.1.2 django-heroku==0.3.1 django-redis==4.10.0 docutils==0.15.2 gunicorn==19.9.0 idna==2.8 importlib-metadata==0.19 kombu==4.6.4 oauthlib==3.1.0 psycopg2==2.8.3 pycodestyle==2.5.0 PySocks==1.7.0 python3-openid==3.1.0 pytz==2019.2 redis==3.3.8 requests==2.22.0 requests-oauthlib==1.2.0 six==1.12.0 sqlparse==0.3.0 tweepy==3.8.0 urllib3==1.25.3 vine==1.3.0 whitenoise==4.1.3 zipp==0.5.2
では、Celeryでタスクキューを実装したDjangoアプリケーションをHeorkuにデプロイする方法を順にまとめていきます。
CeleryとRedisをインストールしよう
この記事はあくまでDjangoにタスクキューを実装する手順の備忘録を目的としているので、CeleryやRedisについては詳しくは解説しません。
Celeryは、セロリです。

一言でいうとPythonのjobqueue処理のフレームワークです。
非同期処理とか、タイムスケジューリングとかいろいろできます。
Redisは、リモートディクショナリサーバーの略で、データベース、キャッシュ、メッセージブローカー、およびキューとして使用するための高速でオープンソースのメモリ内Key-Valueデータストア、だそうです。
とりあえずこの二つが、Djangoでタスクキューを実装するために必要になります。
まずはCeleryのインストールです。
これは普通にpipで入れてあげればOKです。
pip install celery
次はRedisですね。
今回はUbuntu上にインストールするので、aptでインストールしてあげるのですが、残念ながらデフォルトでは最新のRedisはインストールできません。
以下のコマンドで、最新のRedisのリポジトリを追加してからインストールしましょう。
sudo add-apt-repository ppa:chris-lea/redis-server sudo apt update sudo apt install redis-server
無事にインストールに成功したら、このコマンドで正しくインストールができたことを確認しましょう。
redis-cli --version redis-server --version
Redisのインストールが確認できたら、最後にpipでRedisを動かすのに必要なモジュールをインストールします。
pip install django-redis-cache
これで必要なモジュールのインストールが完了しました。
次はローカルで動作させていきます。
ディレクトリ構成とCelery.py
公式ドキュメントのディレクトリツリーをパクって説明していきます。
以下のディレクトリツリーは、最低限のプロジェクトのツリーを表してます。
Celeryが便利だなと感じたのは、アプリケーション側のコードに特に修正を加える必要がなく、プロジェクト側だけで完結する点でした。
- proj/ - manage.py - proj/ - __init__.py - settings.py - celery.py - urls.py
まずはプロジェクトディレクトリの中にcelery.pyというファイルを作りましょう。
以下のコードを記述してください。
{{ own_projectname }}には自分のプロジェクトの名前を入れてあげてください。
# celery.py import os from celery import Celery # set the default Django settings module for the 'celery' program. settings = os.getenv( "DJANGO_SETTINGS_MODULE", "{{ own_projectname }}.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings) app = Celery('{{ own_projectname }}') # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. # - namespace='CELERY' means all celery-related configuration keys # should have a `CELERY_` prefix. app.config_from_object('django.conf:settings', namespace='CELERY') # Load task modules from all registered Django app configs. app.autodiscover_tasks(['{{ own_projectname }}'])
Setting.pyの編集
次にsetting.pyを編集します。
まずはINSTALLED_APPSにdjango_celery_resultsを追加してあげましょう。
INSTALLED_APPS = [ ・・・ 'django_celery_results', ]
追記が終わったらmigrateを忘れずに。
python manage.py migrate
これでdjango_celery_resultsのモデルが作成されて処理のログを確認できるようになります。
次は、Setting.pyの末尾にこちらを追記してください。
BROKER_URLとRESULT_BACKENDを指定してあげます。
ローカルで動かすときとHerokuにデプロイするときで記述が異なるので注意。
#ローカルのみ CELERY_BROKER_URL = "redis://localhost:6379/1" CELERY_RESULT_BACKEND = "django-db" #Herokuにデプロイするときはこっち #CELERY_BROKER_URL = os.environ.get("REDIS_URL") #CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")
Celeryの非同期処理を起動してみる
ここまでで最低限の設定は完了しました。
いよいよ実際に動かしてみましょう。
まずはRedisを起動。
sudo service redis-server start sudo systemctl enable redis-server
次にCeleryを起動。
sudo systemctl daemon-reload sudo service celery start sudo systemctl enable celery
非同期で処理させたいジョブを指定。
※ここは既存のメソッドで大丈夫です。すでにあるアプリケーションをそのまま編集しましょう。
from {{ own_projectname }}.celery import app #非同期処理させたいメソッド @app.task def job(a,b): return a + b #delayを付けて関数を呼び出すと非同期処理がされる。 job.delay(1,2)
最後に起動コマンド。
runserverはしておく必要があります。
celery worker -A webapp.celery -l INFO
このコマンドが通れば、無事にworkerが起動され、指定した処理が非同期で実行されるはずです。
確認してみましょう。
Herokuにデプロイする
アプリケーションはローカルで正常に実行されている前提とします。
まずはHerokuにRadisアドオンを追加します。
無料枠でも使えるので安心。
heroku addons:create heroku-redis:hobby-dev -a {{ own_herokuapp }}
次に、前述の通りsetting.pyを書き換えましょう。
#ローカルのみ #CELERY_BROKER_URL = "redis://localhost:6379/1" #CELERY_RESULT_BACKEND = "django-db" #Herokuにデプロイするときはこっち CELERY_BROKER_URL = os.environ.get("REDIS_URL") CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")
ここまで出来たら、いつも通りデプロイしましょう。
git push heroku master heroku ps:scale worker=1
デプロイに成功すれば完成です!
正しく動いてくれているかどうか、ログを確認してみてください。
お疲れ様でした。
まとめ
これで無事にDjangoにタスクキューを実装して、時間のかかる処理をバックで処理させて画面を更新できるようになりました。
非同期処理をできるようにしたら、自分のアプリケーションが一気にグレードアップしたように感じられて、非常に感動しました。
ぜひやってみてください。
今後の課題としては、Redisがちょいちょい落ちてエラーになるのを解消することです。
“Error 110 while writing to socket. Connection timed out.”みたいなエラーがたまに返ってきます。
更新すると復活するんですが。
ちなみに、今回タスクキューを実装したのはこちらのWEBアプリケーションです。
よければ使ってみてください。
やったー!
せろりでタスクキューの実装できたー!
これで今までの『自動ふぁぼ処理全部終わるまでの30秒帰れません現象』が解消された!
嬉しい!MINIBOT
ー日本一シンプルなTwitterBOTーhttps://t.co/28iSLYW9ku— かしわばゆき (@yuki_kashiwaba) August 21, 2019
参考
Celeryの公式様
CeleryをDjangoで動かす
Using Celery on Heroku
django-redis documentation