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):