sql >> Base de Datos >  >> NoSQL >> Redis

¿Cómo devuelvo el render_template del matraz después de que se realiza el trabajo en segundo plano de Redis?

Una solución básica pero factible (esencial):

Puede hacer esto simplemente redirigiendo desde la ruta que pone en cola el trabajo, luego haga que una etiqueta meta actualice esa página periódicamente. Primero importe las bibliotecas requeridas:

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

Configure las conexiones relacionadas con rq y defina la función a ejecutar:

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

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

Luego defina una plantilla que pueda actualizar la página cada 5 segundos:

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

También crearemos una función auxiliar para devolver esa plantilla con una variable insertada, usando el matraz render_template_string . Tenga en cuenta que el valor predeterminado de actualización es Falso, si no se proporciona:

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

Ahora haga una ruta que pondrá en cola nuestra función, obtenga su ID de trabajo rq, luego devuelva una redirección al result ver con ese id . Esto solo toma la entrada en la cadena de URL, pero podría obtenerla desde cualquier lugar:

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

Ahora manejemos el resultado real, con la ayuda de rq.Job objeto. La lógica aquí podría modificarse, ya que esto provocará una actualización de la página en todos los valores excepto "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)

Si el estado es "finished" luego job.result contendrá el valor de retorno de slow_func , por lo que representamos esto en la página.

Este método tiene la desventaja de generar varias solicitudes al servidor, mientras se espera la finalización del trabajo. La etiqueta de actualización meta puede ser un poco poco convencional. Si está enviando la solicitud de una actualización desde Javascript, existen soluciones que pueden enviar la solicitud AJAX en un intervalo, aunque esto sufre el mismo problema de solicitud múltiple.

La alternativa es usar websockets o SSE para transmitir el resultado del trabajo completado a la interfaz tan pronto como se complete.

ACTUALIZACIÓN:27 de febrero de 2021

Decidí probar el método SSE para actualizar la interfaz con el estado del trabajo. Aprendí que rq tiene soporte nativo para actualizar un meta atributo dentro del trabajo, importando rq.get_current_job dentro del trabajo, al que luego se puede acceder externamente después de actualizar el trabajo.

Vea el código de demostración para:

Un ejemplo básico con una barra de progreso (esencial):