sql >> Database teknologi >  >> NoSQL >> Redis

Hvordan returnerer jeg flask render_template efter Redis-baggrundsjobbet er udført?

En grundlæggende, men brugbar løsning (gist):

Du kan gøre dette ved blot at omdirigere fra den rute, der sætter jobbet i kø, og derefter få et metatag til at opdatere siden med jævne mellemrum. Importer først de nødvendige biblioteker:

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

Opsæt de rq-relaterede forbindelser, og definer den funktion, der skal køres:

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

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

Definer derefter en skabelon, som kan opdatere siden hvert 5. sekund:

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

Vi laver også en hjælpefunktion til at returnere den skabelon med en variabel indsat ved hjælp af kolbe render_template_string . Bemærk, at opdatering er som standard Falsk, hvis den ikke er angivet:

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

Lav nu en rute, som sætter vores funktion i kø, få dens rq job-id, og returner derefter en omdirigering til result se med det id . Dette tager bare input i URL-strengen, men kunne hente det fra hvor som helst:

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

Lad os nu håndtere det faktiske resultat ved hjælp af rq.Job objekt. Logikken her kunne justeres, da dette vil forårsage en sideopdatering på alle værdier undtagen "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)

Hvis status er "finished" derefter job.result vil indeholde returværdien af ​​slow_func , så vi gengiver dette på siden.

Denne metode har den ulempe, at den forårsager flere forespørgsler til serveren, mens man venter på, at opgaven er færdig. Meta refresh-tagget kan være lidt ukonventionelt. Hvis du sender anmodningen om en opdatering fra Javascript, er der løsninger, der kan sende AJAX-anmodningen med et interval, selvom dette lider af det samme problem med flere anmodninger.

Alternativet er at bruge websockets eller SSE til at streame resultatet af det færdige job til frontend, så snart det er færdigt.

OPDATERING:27. februar 2021

Jeg besluttede at prøve SSE-metoden til at opdatere frontend med jobstatus. Jeg lærte at rq har indbygget understøttelse til at opdatere en meta attribut i jobbet ved at importere rq.get_current_job inde i jobbet, som så kan tilgås eksternt efter jobopdatering.

Se demonstrationskoden for:

Et grundlæggende eksempel med en statuslinje (gist):




  1. Brugerdefinerede funktioner beregnede kolonner mongodb projektion

  2. MongoDB feltrækkefølge og dokumentpositionsændring efter opdatering

  3. Hvad er en god strategi til at gruppere lignende ord?

  4. MongoDB $dayOfYear