Redis后台作业完成后,如何返回flask render_template? [英] How do I return flask render_template after the Redis background job is done?

查看:79
本文介绍了Redis后台作业完成后,如何返回flask render_template?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have this web app in a flask where I want to execute some ML and AI algorithms after a form is submitted. I am running the ML and AI algorithms in a background job with the help of Redis and rq ( because I have my app hosted by Heroku and they have this timeout thing where you have to return a response within 30 seconds). After the job is done I would like to get the images made by the algorithms ( some graphs ) and output them in a web page, but I have no idea how to render a template in a job function, and importing the app from the flask app to do that doesn't seem to work. Do you have any ideas on how to solve this?

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

my code fragment from the flask app that enqueues a job:

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

我的作业功能代码片段:

my code fragment from the job function:

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

预先感谢

推荐答案

基本但可行的解决方案(要点):

您可以通过从进入工作队列的路由重定向,然后让meta标签定期刷新该页面来实现此目的.首先导入所需的库:

A basic but workable solution (gist):

You could do this by just redirecting from the route which enqueues the job, then have a meta tag refresh that page periodically. First import the required libraries:

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相关的连接,并定义要运行的功能:

Set up the rq related connections, and define the function to run:

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

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

然后定义一个模板,该模板可以每5秒刷新一次页面:

Then define a template which can refresh the page every 5 seconds:

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

我们还将使用烧瓶render_template_string创建一个辅助函数,以返回插入了变量的模板.请注意,如果未提供,则刷新默认为False:

We'll also make a helper function to return that template with a variable inserted, using flask render_template_string. Notice that refresh defaults to False, if not supplied:

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

现在创建一条路线,该路线将使我们的函数入队,获取其rq job-id,然后使用该id将重定向返回到result视图.这只需要输入URL字符串,但是可以从任何地方获取它:

Now make a route which will enqueue our function, get its rq job-id, then return a redirect to the result view with that id. This just takes input in the URL string, but could get that from anywhere:

@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"以外的所有值的页面刷新:

Now let's handle the actual result, with the help of the rq.Job object. The logic here could be tweaked, as this will cause a page refresh on all values except "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的返回值,因此我们将其呈现在页面上.

If the status is "finished" then job.result will contain the return value of slow_func, so we render this on the page.

此方法的缺点是在等待作业完成的同时,会向服务器发出多个请求.元刷新标签可能有点不常规.如果您要从Javascript发送更新请求,则有解决方案可以每隔一段时间发送AJAX请求,尽管它也遇到相同的多请求问题.

This method has the disadvantage of causing several requests to the server, whilst waiting for job completion. The meta refresh tag may be a bit unconventional. If you're sending the request for an update from Javascript, then there are solutions which can send the AJAX request at an interval, though this suffers from the same multiple request problem.

另一种选择是使用websockets或SSE,将完成的作业的结果在完成后立即流式传输到前端.

The alternative is to use websockets, or SSE to stream the result of the completed job to the frontend as soon as it completes.

这篇关于Redis后台作业完成后,如何返回flask render_template?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆