You need to enable JavaScript to run this app. 在Heroku基于Python Flask开发API时如何等待Worker处理完成后返回响应
优惠活动
大模型
产品
解决方案
定价
更多

在Heroku基于Python Flask开发API时如何等待Worker处理完成后返回响应

核心实现逻辑

你当前的实现是将任务投递到RQ队列后立刻返回任务ID,属于异步即发即走模式,要实现等Worker执行完成后再向客户端返回结果,只需要在路由逻辑中增加任务状态轮询等待流程,拿到Worker的执行结果后再组装JSON响应即可,整个过程不需要修改Worker端的业务代码。

代码修改方案

在你原有POST路由的基础上,增加状态轮询的等待逻辑,适配Heroku平台的请求超时规则,修改后的完整代码如下:

from flask import jsonify
import time

# 你原有初始化队列、定义login_to_website函数的逻辑保持不变
@app.route('/', methods=['POST'])
def automate():
    orderNumbers.clear()
    email = request.args.get('email', None)
    password = request.args.get('password', None)
    orderNumber = request.args.get('orderNumber', None)
    orderNumbers.append(orderNumber)
    
    # 投递任务到队列,拿到任务实例
    job = q.enqueue(login_to_website, email, password, orderNumber)
    job_key = job.get_id()

    # 轮询等待Worker执行完成
    max_wait_time = 25  # 预留5秒余量,适配Heroku 30秒请求超时阈值
    waited_duration = 0
    poll_interval = 0.5  # 每0.5秒查询一次任务状态,降低Redis请求压力

    while waited_duration < max_wait_time:
        # 同步刷新任务的最新状态
        job.refresh()
        # 任务执行成功,返回结果
        if job.get_status() == 'finished':
            return jsonify({
                "task_id": job_key,
                "status": "success",
                "result": job.result
            })
        # 任务执行失败,返回错误信息
        if job.get_status() == 'failed':
            return jsonify({
                "task_id": job_key,
                "status": "failed",
                "error": str(job.exc_info)
            })
        # 任务还在运行,进入休眠等待
        time.sleep(poll_interval)
        waited_duration += poll_interval

    # 等待超时的兜底返回
    return jsonify({
        "task_id": job_key,
        "status": "timeout",
        "message": "任务超过最大等待时长,请稍后通过任务ID查询执行结果"
    })
关键注意事项
  • 严格控制最大等待时长:Heroku平台对Web请求的最长允许处理时间是30秒,超过这个阈值平台会主动断开请求连接,所以等待上限必须留足余量,设置在25秒以内。
  • 轮询间隔不要过短:保持0.5-1秒的查询间隔即可,过短的查询频率会给Redis服务带来不必要的压力,也会额外消耗Web进程的运行时长。
  • 注意全局变量的线程安全问题:你当前代码里用全局列表orderNumbers存储临时订单号,多请求并发时会出现数据互相覆盖的问题,后续可以把这类临时数据存在任务的元数据或者Redis缓存中,不要依赖进程内的全局变量存请求级数据。
  • 不要跳过任务状态刷新步骤:拿到的初始job对象是入队时的快照,不调用job.refresh()同步最新状态的话,会一直拿到入队时的初始状态,陷入死循环。

内容的提问来源于stack exchange,提问作者nader sayed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 18:06:04