sql >> Database >  >> NoSQL >> Redis

Hoe retourneer ik flask render_template nadat de Redis-achtergrondtaak is voltooid?

Een eenvoudige maar werkbare oplossing (kern):

U kunt dit doen door gewoon om te leiden vanaf de route die de taak in de wachtrij plaatst, en vervolgens een metatag die pagina periodiek te laten vernieuwen. Importeer eerst de benodigde bibliotheken:

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

Stel de rq-gerelateerde verbindingen in en definieer de functie die moet worden uitgevoerd:

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

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

Definieer vervolgens een sjabloon die de pagina elke 5 seconden kan vernieuwen:

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

We zullen ook een helperfunctie maken om die sjabloon terug te geven met een variabele ingevoegd, met behulp van flask render_template_string . Merk op dat vernieuwen standaard is ingesteld op False, indien niet opgegeven:

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

Maak nu een route die onze functie in de wachtrij zal zetten, haal de rq job-id op en retourneer een omleiding naar het result bekijken met die id . Dit vereist alleen invoer in de URL-tekenreeks, maar kan die overal vandaan halen:

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

Laten we nu het werkelijke resultaat behandelen, met behulp van de rq.Job voorwerp. De logica hier kan worden aangepast, omdat dit een paginavernieuwing veroorzaakt voor alle waarden behalve "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)

Als de status "finished" is dan job.result bevat de retourwaarde van slow_func , dus we geven dit weer op de pagina.

Deze methode heeft het nadeel dat er meerdere verzoeken naar de server worden gestuurd, terwijl wordt gewacht op het voltooien van de taak. De meta-verversingstag is misschien een beetje onconventioneel. Als u het verzoek voor een update vanuit Javascript verzendt, zijn er oplossingen die het AJAX-verzoek met een interval kunnen verzenden, hoewel dit hetzelfde probleem met meerdere verzoeken heeft.

Het alternatief is om websockets of SSE te gebruiken om het resultaat van de voltooide taak naar de frontend te streamen zodra deze is voltooid.

UPDATE:27 februari 2021

Ik besloot om de SSE-methode te proberen om de frontend bij te werken met de taakstatus. Ik heb geleerd dat rq heeft native ondersteuning voor het bijwerken van een meta attribuut binnen de taak, door rq.get_current_job . te importeren binnen de taak, die vervolgens extern kan worden geopend na het vernieuwen van de taak.

Zie de demonstratiecode voor:

Een eenvoudig voorbeeld met een voortgangsbalk (kern):




  1. MongoDB en CodeIgniter

  2. Integreer Redis met JHipster CacheConfiguratiefout

  3. Hoe stel ik de standaardwaarde van een geheel getal in mongodb in?

  4. hoe je onderliggende objecten in mongodb kunt opvragen