Solusi dasar tetapi bisa diterapkan (inti):
Anda dapat melakukan ini hanya dengan mengarahkan ulang dari rute yang mengantrekan pekerjaan, lalu minta meta tag menyegarkan halaman itu secara berkala. Pertama-tama impor pustaka yang diperlukan:
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
Siapkan koneksi terkait rq, dan tentukan fungsi yang akan dijalankan:
r = Redis(host='redisserver')
q = Queue(connection=r)
def slow_func(data):
sleep(5)
return 'Processed %s' % (data,)
Kemudian tentukan template yang dapat menyegarkan halaman setiap 5 detik:
template_str='''<html>
<head>
{% if refresh %}
<meta http-equiv="refresh" content="5">
{% endif %}
</head>
<body>{{result}}</body>
</html>'''
Kami juga akan membuat fungsi pembantu untuk mengembalikan template itu dengan variabel yang dimasukkan, menggunakan labu render_template_string
. Perhatikan bahwa penyegaran default ke False, jika tidak disertakan:
def get_template(data, refresh=False):
return render_template_string(template_str, result=data, refresh=refresh)
Sekarang buat rute yang akan mengantrekan fungsi kita, dapatkan rq job-id-nya, lalu kembalikan redirect ke result
lihat dengan id
itu . Ini hanya membutuhkan input dalam string URL, tetapi bisa mendapatkannya dari mana saja:
@app.route('/process/<string:data>')
def process(data):
job = q.enqueue(slow_func, data)
return redirect(url_for('result', id=job.id))
Sekarang mari kita tangani hasil sebenarnya, dengan bantuan rq.Job
obyek. Logika di sini dapat diubah, karena ini akan menyebabkan penyegaran halaman pada semua nilai kecuali "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)
Jika statusnya "finished"
lalu job.result
akan berisi nilai kembalian slow_func
, jadi kami merender ini di halaman.
Metode ini memiliki kelemahan menyebabkan beberapa permintaan ke server, sambil menunggu penyelesaian pekerjaan. Tag penyegaran meta mungkin agak tidak konvensional. Jika Anda mengirim permintaan pembaruan dari Javascript, maka ada solusi yang dapat mengirim permintaan AJAX pada suatu interval, meskipun ini mengalami masalah beberapa permintaan yang sama.
Alternatifnya adalah menggunakan soket web, atau SSE untuk mengalirkan hasil pekerjaan yang telah diselesaikan ke frontend segera setelah selesai.
PERBARUI:27 Feb 2021
Saya memutuskan untuk mencoba metode SSE memperbarui frontend dengan status pekerjaan. Saya mengetahui bahwa rq
memiliki dukungan asli untuk memperbarui meta
atribut dalam pekerjaan, dengan mengimpor rq.get_current_job
di dalam pekerjaan, yang kemudian dapat diakses secara eksternal setelah pembaruan pekerjaan.
Lihat kode demonstrasi untuk:
Contoh dasar dengan bilah kemajuan (inti):