Redis
 sql >> база данни >  >> NoSQL >> Redis

Как да върна flask render_template, след като работата на фона на Redis приключи?

Основно, но работещо решение (същност):

Можете да направите това, като просто пренасочите от маршрута, който поставя заданието в опашка, след което накарате метатаг да опреснява тази страница периодично. Първо импортирайте необходимите библиотеки:

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 вътре в заданието, което след това може да бъде достъпно отвън след опресняване на заданието.

Вижте демонстрационния код за:

Основен пример с лента за напредък (същност):




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Как да използвам Redis масово вмъкване?

  2. Как да стартирам анализ на паметта на AWS ElastiCache?

  3. Влияе ли дължината на името на производителността в Redis?

  4. Актуализирайте обекта в redis с spring-data-redis

  5. Фатална грешка:Неуловено изключение „RedisException“ със съобщение „Redis сървърът изчезна“