sql >> Databáze >  >> NoSQL >> Redis

Jak vrátím flask render_template po dokončení úlohy na pozadí Redis?

Základní, ale funkční řešení (podstata):

Můžete to udělat pouhým přesměrováním z trasy, která zařazuje úlohu do fronty, a poté nechat metaznačku pravidelně obnovovat tuto stránku. Nejprve importujte požadované knihovny:

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

Nastavte připojení související s rq a definujte funkci, která se má spustit:

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

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

Poté definujte šablonu, která může obnovovat stránku každých 5 sekund:

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

Vytvoříme také pomocnou funkci, která vrátí tuto šablonu s vloženou proměnnou pomocí flask render_template_string . Všimněte si, že obnovovací výchozí hodnota je False, pokud není zadána:

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

Nyní vytvořte cestu, která zařadí naši funkci do fronty, získá její rq job-id a poté vrátí přesměrování na result zobrazit s tímto id . To pouze bere vstup v řetězci adresy URL, ale lze jej získat odkudkoli:

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

Nyní zpracujme skutečný výsledek pomocí rq.Job objekt. Logiku zde lze vyladit, protože to způsobí obnovení stránky u všech hodnot kromě "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)

Pokud je stav "finished" pak job.result bude obsahovat návratovou hodnotu slow_func , takže to vykreslíme na stránce.

Tato metoda má nevýhodu v tom, že způsobuje několik požadavků na server, zatímco čeká na dokončení úlohy. Meta refresh tag může být trochu netradiční. Pokud posíláte požadavek na aktualizaci z Javascriptu, pak existují řešení, která mohou posílat požadavek AJAX v intervalu, i když to trpí stejným problémem s více požadavky.

Alternativou je použít websockets nebo SSE pro streamování výsledku dokončené úlohy do frontendu, jakmile bude dokončena.

AKTUALIZACE:27. února 2021

Rozhodl jsem se vyzkoušet metodu SSE aktualizace frontendu se stavem úlohy. Naučil jsem se, že rq má nativní podporu pro aktualizaci meta atribut v rámci úlohy importem rq.get_current_job uvnitř úlohy, ke které pak lze přistupovat externě po obnovení úlohy.

Viz ukázkový kód pro:

Základní příklad s ukazatelem průběhu (gist):




  1. Spring data mongodb - Je vyžadována volba 'kurzor'

  2. MongoDB $cond

  3. Jak nasadit MongoDB pro vysokou dostupnost

  4. 4 způsoby aktualizace dokumentu v MongoDB