Heroku自动缩容Dyno时Passenger引发H13错误求助
解决Heroku缩容时的H13错误问题
我完全懂你遇到的麻烦——Heroku自动缩容关闭Dyno时,Passenger会立刻终止所有未完成的请求,直接导致连接提前断开触发H13错误。从你贴的日志也能看出来,核心问题就是Passenger对SIGTERM信号的处理太激进,没给正在跑的请求留完成的时间。
下面是几个经过实践验证的解决方案,按优先级给你整理好了:
1. 配置Passenger的优雅关闭超时
Passenger默认收到SIGTERM后会立刻终止请求,我们可以通过环境变量让它等一等正在处理的请求:
- 打开Heroku应用的设置页面,添加环境变量:
这里的PASSENGER_GRACEFUL_SHUTDOWN_TIMEOUT=3030是等待的秒数,你可以根据自己应用里请求的平均处理时长调整(注意Heroku本身给Dyno的关闭宽限期就是30秒,别超过这个值)。
2. 代码层捕获SIGTERM,自定义优雅关闭逻辑
如果Passenger的默认配置还不够灵活,你可以在应用代码里直接捕获SIGTERM信号,拒绝新请求的同时等待现有请求完成:
- 拿Rails应用举例子,在
config/application.rb里加这段代码:
这样收到SIGTERM后,应用会给新请求返回503,同时让正在处理的请求继续跑完,直到超时。shutdown_requested = false Signal.trap('TERM') do shutdown_requested = true Rails.logger.info "收到SIGTERM信号,开始优雅关闭" end # 自定义中间件拦截新请求 class ShutdownMiddleware def initialize(app) @app = app end def call(env) if shutdown_requested [503, {'Content-Type' => 'text/plain'}, ["服务正在关闭,请稍后再试"]] else @app.call(env) end end end config.middleware.use ShutdownMiddleware
3. 调整Heroku的缩容策略(可选)
如果你的应用有不少长耗时请求,还可以从缩容触发逻辑上优化:
- 避免在请求高峰期自动缩容,用Heroku的
autoscaling插件自定义缩容条件,比如只有当请求量持续低于阈值10分钟以上再触发缩容。 - 或者用蓝绿部署的思路替换Dyno:先启动新的Dyno实例,等所有新请求都路由到新实例后,再慢慢关闭旧Dyno,从根源上避免缩容时打断请求。
最后提醒一句:Heroku给Dyno的关闭宽限期最多30秒,所有优雅关闭的逻辑都得在这个时间内完成,超时后Heroku会发SIGKILL强制终止进程,到时候还是会出现H13错误,所以一定要根据自己请求的实际处理时长来设置超时时间。
内容的提问来源于stack exchange,提问作者Manu Kanthan
相关产品推荐
相关产品推荐

