基本的で実行可能なソリューション(要点):
これを行うには、ジョブをエンキューするルートからリダイレクトし、メタタグでそのページを定期的に更新します。まず、必要なライブラリをインポートします:
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
rq関連の接続を設定し、実行する関数を定義します。
r = Redis(host='redisserver')
q = Queue(connection=r)
def slow_func(data):
sleep(5)
return 'Processed %s' % (data,)
次に、5秒ごとにページを更新できるテンプレートを定義します。
template_str='''<html>
<head>
{% if refresh %}
<meta http-equiv="refresh" content="5">
{% endif %}
</head>
<body>{{result}}</body>
</html>'''
また、flask render_template_string
を使用して、変数が挿入されたテンプレートを返すヘルパー関数を作成します。 。提供されていない場合、更新はデフォルトでFalseになっていることに注意してください:
def get_template(data, refresh=False):
return render_template_string(template_str, result=data, refresh=refresh)
次に、関数をエンキューするルートを作成し、そのrq job-idを取得してから、result
へのリダイレクトを返します。 そのid
で表示 。これはURL文字列に入力するだけですが、どこからでも取得できます:
@app.route('/process/<string:data>')
def process(data):
job = q.enqueue(slow_func, data)
return redirect(url_for('result', id=job.id))
次に、rq.Job
を使用して、実際の結果を処理しましょう。 物体。 "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)
ステータスが"finished"
の場合 次にjob.result
slow_func
の戻り値が含まれます 、ページにこれをレンダリングします。
この方法には、ジョブの完了を待機している間にサーバーに複数の要求を発生させるという欠点があります。メタリフレッシュタグは少し型破りかもしれません。 Javascriptから更新のリクエストを送信する場合、AJAXリクエストを間隔を置いて送信できるソリューションがありますが、これには同じ複数のリクエストの問題があります。
別の方法は、WebSocketまたはSSEを使用して、完了したジョブの結果を完了したらすぐにフロントエンドにストリーミングすることです。
更新:2021年2月27日
フロントエンドをジョブステータスで更新するSSEメソッドを試してみることにしました。 rq
meta
の更新をネイティブでサポートしています rq.get_current_job
をインポートすることにより、ジョブ内の属性 ジョブの内部。ジョブの更新後に外部からアクセスできます。
次のデモコードを参照してください:
プログレスバー(要点)を使用した基本的な例: