Redis后台作业完成后如何返回flask render_template? (要点)

问题描述 投票:1回答:1

我将这个Web应用程序放在一个烧瓶中,在提交表单后,我想在其中执行一些ML和AI算法。我在Redis和rq的帮助下在后台作业中运行ML和AI算法(因为我的应用程序由Heroku托管,并且它们存在超时问题,您必须在30秒内返回响应)。作业完成后,我想获取算法生成的图像(一些图形)并将其输出到网页中,但是我不知道如何在作业函数中渲染模板,以及如何从烧瓶中导入应用程序应用程序似乎无法正常工作。您对如何解决此问题有任何想法吗?

我的烧瓶应用程序中的使工作入队的代码片段:

def upload():
    from mlsalespred import run_model
    file = request.files['file']
    dffile = pd.read_csv(file)
    job = q.enqueue(run_model, dffile)
    return render_template("waiting.html")

我的工作职能代码片段:

def run_model(dataFrame):
    - - - - - - - - - - -
    - - some ml stuff - -
    - - - - - - - - - - -
    return render_template("uploaded.html", sales_fig = sales_fig.decode('utf8'), diff_fig = diff_fig.decode('utf8'), pred_fig = pred_fig.decode('utf8') )

提前感谢

flask redis jobs worker task-queue
1个回答
0
投票

一个基本但可行的解决方案(gist)

您可以通过从进入作业的路由中进行重定向,然后让meta标签定期刷新该页面来完成此操作。首先导入所需的库:

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>'''

我们还将使用瓶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发送更新请求,那么solutions可以每隔一段时间发送AJAX请求,尽管这也遇到相同的多请求问题。

替代方法是使用websockets或SSE,一旦完成,就将完成的作业的结果流式传输到前端。

© www.soinside.com 2019 - 2024. All rights reserved.