はじめに
Flaskで簡単なpythonアプリケーションを作成していました。そこで非同期処理を追加したいと思いました。
しかし、そこでいくつか詰まるポイントがあったため記事にしました。
1つ、先に言えることはpythonでの非同期処理はFlaskではないフレームワークの方が良いかもしれないということです。ググっていると他のフレームワークの方が情報が多く感じました。
実行内容
ユーザーがテキストボックスに2つの数字を打ち込み、ボタンを押す。
サーバー側は2つの数字を足し合わせる操作を非同期処理で行い、ユーザーへのレスポンスをすぐ返す。
実行環境
os: Windows10
redis Redis-x64-3.0.504.msi
python 3.5.6 (Anaconda)
Flask==1.1.1
celery==3.1.25
redis==2.10.6
実行手順
-
Anaconda Promptで「python sample.py」を実行する。
-
Anaconda Promptで 「celery -A sample.celery worker -l info」を実行する。
-
結果として、すぐにレスポンスが返る。celeryを実行したAnaconda Promptに計算結果が表示されていることを確認する。
つまづきポイント
-
celeryとredisのバージョンには相性があるのでまずは、これらを確認する。
-
redisがlocalhost:6397で動いているか確認する。
-
非同期処理する関数がceleryのtaskに登録されているか確認する。
(「celery -A sample.celery worker -l info」を実行したターミナル上で確認可能)
おわりに
簡単ですが、以下にsample.py, main.htmlを添付しました。この2ファイルで動きます。参考にしたサイトのURLも添付しておきました。
なにか質問、間違いがあればぜひコメントお願いします。
ソースコード
# coding=utf-8
from flask import Flask, render_template, request
# Flaskアプリ準備
app = Flask("sample")
# this is a part of celery property to use in Flask
from celery import Celery
def make_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
# update flask config to use celery
app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(app)
@celery.task()
def add(a, b):
print(a + b)
return a + b
@app.route('/', methods=["GET", "POST"])
def sample():
# POST時の処理
if request.method == 'POST':
return render_template(
'main.html', # 表示するHTMLファイル
)
# GET時の処理
else:
return render_template(
'main.html', # 表示するHTMLファイル
)
@app.route('/celery', methods=["POST"])
def celery_test():
if request.method == 'POST':
a = int(request.form["num_one"])
b = int(request.form["num_two"])
result = add.delay(a,b)
return render_template(
'main.html', # 表示するHTMLファイル
)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=9000)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<title>Sample</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>
<p align="center">
<font size="10">Flask 非同期処理</font>
</p>
</h1>
</div>
<form class="" method="post" action="/celery" enctype="multipart/form-data">
<div class="container" style="text-align: center;">
<input type="number" name="num_one"> +
<input type="number" name="num_two">
</div>
<div class="button_wrapper" style="text-align: center;">
<button type="submit" class="btn btn-lg btn-success" style="margin-top: 50px; ">計算実行</button>
</div>
</form>
</div>
</body>
</html>
参考文献
Windows版Redisをインストールして触ってみる
http://kageura.hatenadiary.jp
Flask公式
https://flask.palletsprojects.com/en/1.0.x/patterns/celery/
python – Celery Workerを起動できない
https://codeday.me/jp/qa/20190525/900758.html
celery AttributeError: 'str' object has no attribute 'items' django Day14
http://www.programmersought.com/article/8120463251/