Создание асинхронной задачи в Flask

Я пишу приложение в колбе, которая работает очень хорошо, за исключением этого WSGI - это синхронно и блокирует. У меня есть одна задача, в частности, которая вызывает сторонний API, и эта задача может занять несколько минут. Я хотел бы сделать этот звонок (на самом деле это серия звонков) и позволить ему работать. пока управление возвращено к склянке.

мой взгляд выглядит так:

@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()

run и предоставьте обратный вызов для выполнения при возврате метода, в то время как Flask может продолжать обрабатывать запросы. Это единственная задача, которую мне нужно запустить асинхронно, и я хотел бы получить несколько советов о том, как лучше всего реализовать это.

Я посмотрел на Twisted и Klein, но я не уверен, что они излишни, так как, возможно, нитей будет достаточно. Или, может быть, сельдерей-хороший выбор для этого?

1 ответов


Я хотел бы использовать сельдерей для обработки асинхронной задачи для вас. Вам нужно будет установить брокера в качестве очереди задач (рекомендуется 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 -A app.celery --loglevel=debug

Я бы также сослался на Мигеля Гринберга написать для более глубокого руководства по использованию сельдерея с колбой.