Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Jak zwrócić flask render_template po zakończeniu pracy w tle Redis?

Podstawowe, ale wykonalne rozwiązanie (istota):

Możesz to zrobić, po prostu przekierowując z trasy, która umieszcza zadanie w kolejce, a następnie okresowo odświeżaj tę stronę za pomocą metatagu. Najpierw zaimportuj wymagane biblioteki:

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

Skonfiguruj połączenia związane z rq i zdefiniuj funkcję do uruchomienia:

r = Redis(host='redisserver')
q = Queue(connection=r)

def slow_func(data):
    sleep(5)
    return 'Processed %s' % (data,)

Następnie zdefiniuj szablon, który może odświeżać stronę co 5 sekund:

template_str='''<html>
    <head>
      {% if refresh %}
        <meta http-equiv="refresh" content="5">
      {% endif %}
    </head>
    <body>{{result}}</body>
    </html>'''

Stworzymy również funkcję pomocniczą, aby zwrócić ten szablon z wstawioną zmienną, używając flask render_template_string . Zwróć uwagę, że odświeżanie jest domyślnie ustawione na False, jeśli nie podano:

def get_template(data, refresh=False):
    return render_template_string(template_str, result=data, refresh=refresh)

Teraz utwórz trasę, która zakolejkuje naszą funkcję, pobierz jej identyfikator zadania rq, a następnie zwróci przekierowanie do result widok z tym id . To po prostu pobiera dane wejściowe w ciągu adresu URL, ale można je uzyskać z dowolnego miejsca:

@app.route('/process/<string:data>')
def process(data):
    job = q.enqueue(slow_func, data)
    return redirect(url_for('result', id=job.id))

Teraz zajmijmy się rzeczywistym wynikiem za pomocą rq.Job obiekt. Logika tutaj może zostać zmodyfikowana, ponieważ spowoduje to odświeżenie strony na wszystkich wartościach z wyjątkiem "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)

Jeśli stan to "finished" następnie job.result będzie zawierać wartość zwracaną przez slow_func , więc renderujemy to na stronie.

Ta metoda ma tę wadę, że powoduje kilka żądań do serwera podczas oczekiwania na zakończenie zadania. Meta tag odświeżania może być nieco niekonwencjonalny. Jeśli wysyłasz żądanie aktualizacji z JavaScript, istnieją rozwiązania, które mogą wysyłać żądanie AJAX w określonych odstępach czasu, chociaż dotyczy to tego samego problemu z wieloma żądaniami.

Alternatywą jest użycie gniazd sieciowych lub SSE do strumieniowego przesyłania wyników ukończonego zadania do interfejsu użytkownika, gdy tylko się zakończy.

AKTUALIZACJA:27 lutego 2021

Postanowiłem wypróbować metodę SSE polegającą na aktualizacji frontendu o status zadania. Dowiedziałem się, że rq ma natywną obsługę aktualizacji meta atrybut w ramach zadania, importując rq.get_current_job wewnątrz zadania, do którego można uzyskać dostęp z zewnątrz po odświeżeniu zadania.

Zobacz kod demonstracyjny dla:

Podstawowy przykład z paskiem postępu (istota):




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Jaka jest dobra strategia grupowania podobnych słów?

  2. Redis jest jednowątkowy, więc jak wykonuje współbieżne operacje we/wy?

  3. Zestaw konfiguracji Redis z węzłem jS

  4. Zookeeper vs In-memory-data-grid vs Redis

  5. Skanowanie klienta ruby ​​redis vs klucze