1. ホーム
  2. python

[解決済み] Flaskで非同期タスクを作る

2022-07-16 06:49:48

質問

私はFlaskでアプリケーションを書いており、以下の点を除いてはとてもうまく動作しています。 WSGI が同期とブロックであることを除いては、とてもうまく動作しています。私はサードパーティのAPIを呼び出す1つのタスクを持っており、そのタスクが完了するまでに数分かかることがあります。私はその呼び出し(実際には一連の呼び出しです)を行い、制御がFlaskに返される間、それを実行させたいと考えています。

私のビューは次のようになります。

@app.route('/render/<id>', methods=['POST'])
def render_script(id=None):
    ...
    data = json.loads(request.data)
    text_list = data.get('text_list')
    final_file = audio_class.render_audio(data=text_list)
    # do stuff
    return Response(
        mimetype='application/json',
        status=200
    )

さて、私がやりたいことは、行の

final_file = audio_class.render_audio()

を実行し、メソッドが戻ったときに実行されるコールバックを提供し、その間Flaskはリクエストの処理を続けることができます。これは、Flaskが非同期で実行する必要がある唯一のタスクであり、私はこれを実装するための最善の方法についてのいくつかのアドバイスをしたいと思います。

私はTwistedとKleinを見ましたが、多分Threadingが十分であるように、私はそれらが過剰であることを確信していません。あるいは、Celeryはこのための良い選択でしょうか?

どのように解決するのですか?

私なら セロリ を使って、非同期タスクを処理することができます。タスクキューとなるブローカーをインストールする必要があります(RabbitMQやRedisがおすすめです)。

app.py :

from flask import Flask
from celery import Celery

broker_url = 'amqp://guest@localhost'          # Broker URL for RabbitMQ task queue

app = Flask(__name__)    
celery = Celery(app.name, broker=broker_url)
celery.config_from_object('celeryconfig')      # Your celery configurations in a celeryconfig.py

@celery.task(bind=True)
def some_long_task(self, x, y):
    # Do some long task
    ...

@app.route('/render/<id>', methods=['POST'])
def render_script(id=None):
    ...
    data = json.loads(request.data)
    text_list = data.get('text_list')
    final_file = audio_class.render_audio(data=text_list)
    some_long_task.delay(x, y)                 # Call your async task and pass whatever necessary variables
    return Response(
        mimetype='application/json',
        status=200
    )

Flaskアプリを実行し、celery workerを実行するために別プロセスを起動します。

$ celery worker -A app.celery --loglevel=debug

また、Miguel Gringbergの 書き込み を参照してください。