Основно, но работещо решение (същност):
Можете да направите това, като просто пренасочите от маршрута, който поставя заданието в опашка, след което накарате метатаг да опреснява тази страница периодично. Първо импортирайте необходимите библиотеки:
from flask import Flask, redirect, url_for, render_template_string
app = Flask(__name__)
from time import sleep
from rq import Queue
from rq.job import Job
from redis import Redis
Настройте свързаните с rq връзки и дефинирайте функцията за изпълнение:
r = Redis(host='redisserver')
q = Queue(connection=r)
def slow_func(data):
sleep(5)
return 'Processed %s' % (data,)
След това дефинирайте шаблон, който може да обновява страницата на всеки 5 секунди:
template_str='''<html>
<head>
{% if refresh %}
<meta http-equiv="refresh" content="5">
{% endif %}
</head>
<body>{{result}}</body>
</html>'''
Ще направим също помощна функция, която да върне този шаблон с вмъкната променлива, като използваме flask render_template_string
. Забележете, че опресняването е по подразбиране на False, ако не е предоставено:
def get_template(data, refresh=False):
return render_template_string(template_str, result=data, refresh=refresh)
Сега направете маршрут, който ще постави в опашката нашата функция, вземете нейния rq job-id, след което върнете пренасочване към result
преглед с този id
. Това просто изисква въвеждане в URL низа, но може да го получи отвсякъде:
@app.route('/process/<string:data>')
def process(data):
job = q.enqueue(slow_func, data)
return redirect(url_for('result', id=job.id))
Сега нека се справим с действителния резултат с помощта на rq.Job
обект. Логиката тук може да бъде променена, тъй като това ще доведе до опресняване на страницата за всички стойности с изключение на "finished"
:
@app.route('/result/<string:id>')
def result(id):
job = Job.fetch(id, connection=r)
status = job.get_status()
if status in ['queued', 'started', 'deferred', 'failed']:
return get_template(status, refresh=True)
elif status == 'finished':
result = job.result
# If this is a string, we can simply return it:
return get_template(result)
Ако състоянието е "finished"
след това job.result
ще съдържа връщаната стойност на slow_func
, така че изобразяваме това на страницата.
Този метод има недостатъка, че причинява няколко заявки към сървъра, докато чака завършване на заданието. Мета маркерът за опресняване може да е малко нетрадиционен. Ако изпращате заявката за актуализация от Javascript, тогава има решения, които могат да изпращат AJAX заявката на интервал, въпреки че това страда от същия проблем с множество заявки.
Алтернативата е да използвате websockets или SSE за поточно предаване на резултата от завършената работа към интерфейса веднага щом завърши.
АКТУАЛИЗИРАНЕ:27 февруари 2021 г.
Реших да пробвам метода на SSE за актуализиране на интерфейса със статус на работа. Научих, че rq
има естествена поддръжка за актуализиране на meta
атрибут в рамките на заданието, като импортирате rq.get_current_job
вътре в заданието, което след това може да бъде достъпно отвън след опресняване на заданието.
Вижте демонстрационния код за:
Основен пример с лента за напредък (същност):