You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Heroku+Gunicorn+gevent环境下Flask应用启动多线程超时如何解决

问题解决办法

核心问题根源

  • 你使用gevent worker时没有提前打猴子补丁,标准库threading创建的线程会阻塞gevent的事件循环,导致worker进程无法向Gunicorn主进程发送心跳,触发30秒默认超时被主进程强制杀死,请求只能等新worker启动后才能返回,所以耗时极长。
  • Heroku路由器本身存在30秒请求硬超时限制,任何web请求超过30秒未返回都会被路由直接断开。
  • 在web进程中运行永久循环的常驻任务不符合架构设计,web进程的核心职责是处理HTTP请求,常驻任务会持续占用worker资源,只要worker重启(包括代码部署、dyno自动休眠、超时被杀),你的后台线程就会直接销毁,任务完全无法稳定运行。
  • 你示例代码中setDaemon(true)写法错误,Python布尔值为大写True,语法错误也可能导致线程启动异常。

分步解决方案

第一步:修复gevent适配问题

在app.py文件最开头(所有import语句之前)添加gevent猴子补丁代码,让标准库的线程、IO操作全部适配gevent的异步模型:

from gevent import monkey
monkey.patch_all()

# 后续再写import flask、threading等其他代码

修改完成后你的现有代码就可以正常启动后台线程,启动后会立即返回页面,不会再阻塞请求触发超时。

第二步:架构优化(推荐,保证后台任务稳定运行)

不要在web进程中跑永久循环的后台任务,拆分独立的worker进程处理:

  1. 新增Heroku worker dyno,修改Procfile添加worker启动配置:
web: gunicorn -k gevent --worker-connections 100 --timeout 60 app:app
worker: python worker.py
  1. 引入消息队列(可使用Heroku免费Redis Addon,搭配rq轻量队列库),表单提交时往队列发送任务参数,web进程直接返回页面:
# app.py 代码调整
import redis
from rq import Queue
import os

r = redis.from_url(os.getenv("REDIS_URL"))
q = Queue(connection=r)

@app.route("/form", methods=["POST"])
def form():
    q.enqueue(func, request.form["code"])
    return render_template("index.html")
  1. 把永久循环的func逻辑放到worker.py中,由独立的worker进程运行,不会影响web请求的处理。

临时测试方案

如果只是临时测试不想拆分架构,完成第一步打猴子补丁的操作后,在Procfile的gunicorn启动命令中添加--timeout 60参数调大worker超时时间即可,线程启动后请求会立即返回,不会触发30秒超时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:24:00