django-q+supervisorで非同期処理
django-q+supervisorで非同期処理
Django Advent Calendar 2018 3日目
django-q+supervisorで非同期処理が実現できるまでをやります
今回検証用に作ったprojectはgitに上げてます
GitHub - yamakiy/djangoq_example: django-qを利用した非同期実装のメモ
環境
下準備
必要なもの
入れる時に利用したコマンド
yum install supervisor yum install redis pip3 install django-q pip3 install redis
各種設定
django projectのsettings
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_q' # これを足す ] # 今回は裏にmariadbを使ってます DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'example', 'USER': 'example', 'PASSWORD': 'ExamplePassw0rd', 'HOST': 'localhost', 'PORT': '3306' } } # django-qの設定 Q_CLUSTER = { 'workers': 2, # 並行起動するワーカー数 デフォルトはcpu数 'timeout': 60, # workerのタイムアウト時間 defaultはNone 'redis': { 'host': '127.0.0.1', 'port': 6379, 'db': 0, } }
djangoのmigrateを実行
migrateで django_qとつけると他のmigrateが勝手に進行しません
python3.6 manage.py migrate django_q
DBの中を見るとこんな感じでテーブルができてるはず
MariaDB [example]> show tables; +-------------------+ | Tables_in_example | +-------------------+ | django_migrations | | django_q_ormq | | django_q_schedule | | django_q_task | +-------------------+
続いてsupervisorの設定
supervisorはプロセスをデーモン化して管理できる便利ツール
redisのsupervisor設定
/etc/supervisord.d/redis.ini
[program:redis] command=/usr/bin/redis-server /etc/redis.conf autostart=true autorestart=true
続いてdjango-qの設定を入れる
[program:django-q] command = python3.6 /root/django/example_site/manage.py qcluster stopasgroup = true autostart=true autorestart=true
supervisor動作の確認
[root@localhost example_site]# supervisorctl status django-q RUNNING pid 16308, uptime 0:00:03 redis RUNNING pid 16309, uptime 0:00:03
正常に動いてなかったらpythonのpathとかを見直す
簡単な処理をやってみる
ページを見るたびにDB内にlogを保存する処理を非同期実行する
tasks.py
import time import datetime from .models import MyLog # 引数にmessageを受け取り、日付とともにログを保存する def log_save(message): # わかりやすくするため、5秒スリープしてログを保存する time.sleep(5) date_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") MyLog(log_txt=f"{date_str} {message}").save()
views.py
from django_q.tasks import async_task class TopView(TemplateView): template_name = "example_app/top.html" def dispatch(self, request, *args, **kwargs): # 非同期実行でユーザーエージェントをログに保存 async_task("example_app.tasks.log_save", request.META["HTTP_USER_AGENT"]) return super(TopView, self).dispatch(request, *args, **kwargs)
サーバーを動かして確認してみる。
MariaDB [example]> select * from example_app_mylog; +----+-----------------------------------------------------------------------------------------------------------------------------------------+ | id | log_txt | +----+-----------------------------------------------------------------------------------------------------------------------------------------+ | 1 | 2018-11-24 13:48:03 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 | +----+-----------------------------------------------------------------------------------------------------------------------------------------+
サーバーからの応答時間は5秒以内に完了している。 ログも書き込めている。
python manage.py qmonitorでクラスターの状況を確認できる
項目 | 役割 |
---|---|
Host | クラスターが起動しているサーバーのホスト名 |
Id | クラスターのprocess ID(pid) |
State | クラスターのステータス |
Pool | クラスタープール内のworker数 |
TQ | 待機タスク |
RQ | キューの結果の数 しばらくするとクリアされる |
RC | プロセスの失敗、またはtimeoutによって生まれ変わったプロセス数 |
UP | クラスタを起動してから経過した時間 |
python3.6 manage qinfo
Taskは24時間単位の統計を示します 他、現在までのプロセス成功数や失敗数、ワーカーの数などが見れる
終わりに
今回は非同期での簡単な処理実装までをやりました。
もう少し高度な例はこちらの公式を参考にどうぞ。
Examples — Django Q 1.0.1 documentation