首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Redis后台任务完成后如何返回flask render_template?

Redis后台任务完成后如何返回flask render_template?
EN

Stack Overflow用户
提问于 2019-12-26 22:55:02
回答 1查看 776关注 0票数 2

我在一个烧瓶中有这个web应用程序,我想在提交表单后执行一些ML和AI算法。我在Redis和rq的帮助下在后台运行ML和AI算法(因为我的应用程序由Heroku托管,他们有超时的事情,你必须在30秒内返回响应)。工作完成后,我想得到的图像算法(一些图表),并输出到一个网页上,但我不知道如何渲染一个工作职能的模板,并从flask应用程序导入的应用程序似乎不工作。你对如何解决这个问题有什么想法吗?

我的代码片段来自将作业排入队列的flask应用程序:

代码语言:javascript
复制
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")

我的工作函数中的代码片段:

代码语言:javascript
复制
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') )

提前感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-27 11:12:07

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

您只需从将作业入队的路由重定向,然后让meta标记定期刷新该页面,即可完成此操作。首先导入所需的库:

代码语言:javascript
复制
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相关连接,并定义要运行的函数:

代码语言:javascript
复制
r = Redis(host='redisserver')
q = Queue(connection=r)

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

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

代码语言:javascript
复制
template_str='''
    
      {% if refresh %}
        
      {% endif %}
    
    {{result}}
    '''

我们还将使用flask创建一个helper函数来返回插入了变量的模板

render_template_string. 请注意,如果未提供刷新,则默认为False:

代码语言:javascript
复制
def get_template(data, refresh=False):
    return render_template_string(template_str, result=data, refresh=refresh)

现在创建一个将把我们的函数排入队列的路由,获取它的rq job-id,然后返回一个重定向到result用它来查看id.

这只接受URL字符串中的输入,但可以从任何地方获得:

代码语言:javascript
复制
@app.route('/process/')
def process(data):
    job = q.enqueue(slow_func, data)
    return redirect(url_for('result', id=job.id))

现在让我们在rq.Job对象。这里的逻辑可以调整,因为这将导致所有值的页面刷新,除了"finished":

代码语言:javascript
复制
@app.route('/result/')
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请求,尽管这会受到相同的多请求问题的困扰。

另一种方法是使用websockets,即SSE,在作业完成后立即将其结果流式传输到前端。

更新:2021年2月27日

我决定尝试一下SSE的方法,用工作状态更新前端。我学到了这一点rq具有对更新meta属性,通过导入rq.get_current_job在作业内部,然后可以在作业刷新后从外部访问。

请参阅以下演示代码:

一个带有进度条的基本示例(要点)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59490025

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档