【Django】CeleryとRedisで非同期処理を実装する方法

  • Django(Python)でバックエンド側の非同期処理を実装するには?
  • Celeryの使い方とは?
  • Redisの設定方法とは?

本記事ではこのような疑問を解決します。


重たい処理や複数の処理を実行する時に欠かせないのがバックエンド側の非同期処理です。

また、Djangoにおいて非同期処理の実装に利用できるパッケージやモジュールはいくつかありますが、
その中でも多く利用されているのがCeleryとRedisの組み合わせです。


そこで今回はDjangoにおいてCeleryとRedisで非同期処理を実装する方法を解説していきます。

Celeryとは?

CeleryとはPython用のタスクキュー(ジョブキュー)処理フレームワークのことです。

簡単にいうと、処理を分散させて実行できる仕組みを提供するものです。

どのような場面で使うのかを考えるとイメージしやすいと思います。

例えば、ユーザーがブラウザからリクエストを送った時に、
重い処理が間にあると、その処理が完了するまでレスポンスが返ってきません。

この場合、ユーザーはレスポンスが返ってくるまで真っ白な画面を見つめることになります。


一方、Celeryを使って処理を分散させる場合、
リクエストを送った時に重い処理を裏側へ投げて、その処理が完了するのを待たずしてレスポンスを返すことができます。


これにより、ユーザーは裏側で重い処理が行われている間、レスポンスを待たずに画面操作が可能になるのです。


なお、Celeryの仕組みは以下のもので構成されています。

・タスク(ジョブ)
→非同期で実行させる処理を一つにまとめたもの

・キュー
→タスクを格納する入れ物(先に入ったタスクから順に取り出す仕様)

・プロデューサー
→タスクを作成してブローカーに渡す役割を持つもの(Celery Clientが行う)

・ブローカー
→作成されたタスクをキューに登録したり、キューに登録されているタスクをワーカーに渡したりする役割を持つもの(今回はRedisが行う)

・ワーカー(コンシューマー)
→ブローカーによってキューから取り出されたタスクを実際に処理する役割を持つもの(Celery Wokerが行う)

Redisとは?

Redis(Remote Dictionary Server)とはオープンソースの非リレーショナルデータベースの1つです。

Celeryのところで説明した「ブローカー」の役割を担ってくれるものです。

簡単にいうと、「処理(タスク)が格納されている倉庫の番人」と言えます。

なお、今回の内容とはあまり関係ありませんが、Redisの特徴を説明すると、以下の通りです。

・Key-Valueでデータを保存する非リレーショナルデータベースである

・単純なKey-Valueだけでなく複雑な種類のデータも扱える

・コンピューターのメインメモリ上でデータを管理しているので、非常に高速にデータへアクセスできる

・すべてのデータをメモリに保存して照会する(インメモリデータベース)

CeleryとRedisによる非同期処理の実装手順

それでは実装に移ります。

今回は開発環境を想定しているため、
Linuxサーバーにおけるsystemd等を使ったデーモン化は考慮外とします。

Redisをインストールする

まずはRedisをインストールします。

Redisのインストール方法は各OSのパッケージ管理ツールによって異なります。

今回はyumコマンドでインストールを実行します。

$ sudo yum install -y redis

各種Pythonライブラリをインストールする

次に以下の通り、必要なライブラリをインストールしましょう。

○Celeryに関するライブラリ

$ pip install celery django-celery-results
※django-celery-resultsはCeleryでの処理の実行結果を扱うためのライブラリ

○Redisに関するライブラリ

$ pip install django-redis

settings.pyを編集する

ここからはDjangoの各種ファイルを編集していきます。
※Celeryに関係する部分のみ

まずはsettings.pyに以下の記述を追加します。

CELERY_BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = 'django-db'
CELERY_CACHE_BACKEND = 'django-cache'
CELERY_TASK_TRACK_STARTED = True

celery.pyを編集する

次にsettings.pyと同じディレクトリにcelery.pyというファイルを作成します。

celery.pyには以下のような記述をしましょう。

import os
from celery import Celery


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'プロジェクト名.settings')

app = Celery('プロジェクト名')

app.config_from_object('django.conf:settings', namespace='CELERY')

app.autodiscover_tasks()

urls.pyとviews.pyを編集する

最後にurls.pyでURLの設定をし、views.pyにて処理を記述します。

ここではユーザーからのリクエストを受け取ってレスポンスを返す処理と、
その途中にある裏側で行う処理(非同期処理)を記述します。

from django.urls import path

urlpatterns = [
    ・・・
    path('task_1', views.task_1, name='task_1'),
]
from django.http import HttpResponse
from celery import shared_task


@shared_task
def task_2(message):# 裏側で実行される処理
    time.sleep(10)# 10秒待機する
    print(message)

def task_1(request):# 本処理
    message = '非同期処理'
    task_2.delay(message)# delayメソッドでタスクを呼び出す
    return HttpResponse('裏側に処理を投げます!')

実際に処理を走らせてみる

それでは実際に処理を走らせてみましょう。

まずはターミナルを3つ開いて、Django・Redis・Celeryの3つを起動します。

○Django

$ python manage.py runserver

○Redis

$ redis-server

○Celery

$ celery -A プロジェクト名 worker -l INFO

次に本処理として設定したURL(/task_1)へアクセスしてみます。

すると以下の通り処理が実行されるのが確認できます。

[04/Jun/2022 17:27:04] “GET /task_1 HTTP/1.1” 500 68324

本処理のレスポンス画面(Celery)

上記のレスポンスが返された後にtask_2の処理が実行されます。
※今回のアプリ名は「app」

[2022-06-04 17:27:04,847: INFO/MainProcess] Task app.views.task_2[cc7e9d60-7d1a-4abc-bc8a-2973e581de06] received
[2022-06-04 17:27:14,885: WARNING/ForkPoolWorker-1] 非同期処理
[2022-06-04 17:27:14,894: INFO/ForkPoolWorker-1] Task app.views.task_2[cc7e9d60-7d1a-4abc-bc8a-2973e581de06] succeeded in 10.04435609699999s: None

まとめ

以上がDjangoにおいてCeleryとRedisで非同期処理を実装する方法になります。

このように手間をかけることなくバックグラウンドの非同期処理を実装できるのがCeleryです。

本記事ではバックグラウンドの非同期処理を行うための必要最低限な実装を扱いました。

その他、非同期処理のスケジューリングやコマンドオプションの実行などは公式リファレンスをご参考ください。

Celery公式リファレンス