Как перенаправить после работы с сельдереем на Python Flask (не Django!) - PullRequest
0 голосов
/ 12 ноября 2018

Мой полный код - это веб-сайт, который можно получить и преобразовать в mp3 из видео YouTube, сохранить его на S3, а затем вернуть пользователю ссылку S3.

Поскольку я хочу использовать EC2 с низкой производительностью (сэкономить деньги)), а также не блокируйте, чтобы многие люди использовали его одновременно, поэтому я использовал сельдерей для асинхронного выполнения.

После того, как сельдерей выполнил работу, я мог выполнить функцию обратного вызова.Но это отображается только на терминале, как я могу (показать его заменить) перенаправить экран ожидания?

from flask import Flask, render_template, request
from celery import Celery
import youtube_dl

app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://:password@redis-YYYY.cloud.redislabs.com:YYYY/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://:password@redis-YYYY.cloud.redislabs.com:YYYY/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)


def done_download_hook(d):
    if d['status'] == 'finished':
        print('Done downloading, now converting ...')


ydl_opts = {
    'format': 'bestaudio/best',
    'outtmpl': '%(id)s.%(ext)s',
    'postprocessors': [{
        'key': 'FFmpegExtractAudio',
        'preferredcodec': 'mp3',
        'preferredquality': '192',
    }],
    'progress_hooks': [done_download_hook],
}


@celery.task(bind=True)
def download_task(self, link, ydl_opts):
    # some long running task here
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        ydl.download([link])
    # and copy converted file to S3, return/get S3 link
    # I could handle the process from EC2 to S3.

@app.route('/')
def my_form():
    return render_template('hello.html')

# I try some decorators @app.XXXXX but no success.
def test_callback():
    print('it worked and run until here')
    # should redirect user to S3 link, or redirect the page with link to click
    # How can I do that ?
    return 'http://...'


@app.route('/', methods=['POST'])
def my_form_post():
    download_link = request.form['text']
    # download_task.delay(download_link, ydl_opts)
    download_task.apply_async((download_link, ydl_opts),link=test_callback())
    return "please waiting, after done converting, we would redirect you to the link"

1 Ответ

0 голосов
/ 12 ноября 2018

Поскольку celery выполняет задачи отдельным процессом (или несколькими, если вы запускаете несколько экземпляров celery), и вы решили сделать процесс асинхронным, чтобы определить, когда задача завершена, страница в браузере будет приходится опрашивать (т.е. через AJAX). Это означает, что ему понадобится некоторый идентификатор, который можно использовать для запроса статуса / результатов задачи. Простейшим идентификатором, который нужно использовать, является тот, который был возвращен обратно в объект, который вы получили при выполнении задачи. Передайте это при рендеринге страницы, чтобы она была доступна для вызова AJAX.

Метод view для обработки вызова затем будет делать что-то вроде

from celery.result import AsyncResult

@app.route('/taskstatus')
def taskstatus(uuid):
    result = AsyncResult(uuid)
    return HttpResponse(json.dumps({'done': result.ready()}),
                        content_type='application/json')

Когда страница видит done: true, она может делать что угодно (перенаправить, изменить текст или цвет элемента, ...)

...