在 Heroku 上捕获 TERM 信号并发送 QUIT 后,独角兽退出超时。

90
我运行 unicorn 和 sidekiq 的 Heroku 应用程序会出现 R12 退出超时错误。这些错误每天会发生 1 到 2 次,以及每次部署应用程序时都会发生。我知道需要将来自 Heroku 的关闭信号转换为 Unicorn 可以正确响应的信号,但是在下面的 Unicorn 配置中我认为已经这样做了:
worker_processes 3
timeout 30
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts "Unicorn master intercepting TERM and sending myself QUIT instead. My PID is #{Process.pid}"
    Process.kill 'QUIT', Process.pid
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    Rails.logger.info('Disconnected from ActiveRecord')
  end
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts "Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT. My PID is #{Process.pid}"
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    Rails.logger.info('Connected to ActiveRecord')
  end

  Sidekiq.configure_client do |config|
    config.redis = { :size => 1 }
  end
end

我围绕错误的日志如下:

Stopping all processes with SIGTERM
Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT. My PID is 7
Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT. My PID is 11
Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT. My PID is 15
Unicorn master intercepting TERM and sending myself QUIT instead. My PID is 2
Started GET "/manage"
reaped #<Process::Status: pid 11 exit 0> worker=1
reaped #<Process::Status: pid 7 exit 0> worker=0
reaped #<Process::Status: pid 15 exit 0> worker=2
master complete
Error R12 (Exit timeout) -> At least one process failed to exit within 10 seconds of SIGTERM
Stopping remaining processes with SIGKILL
Process exited with status 137

看起来在超时之前所有子进程都已成功结束。主进程是否仍然存活?另外,在关闭期间路由器是否应继续向dyno发送Web请求,如日志所示?

顺便提一下,我正在使用Heroku的零停机部署插件(https://devcenter.heroku.com/articles/labs-preboot/)。


6
如果有帮助的话,我也遇到了这个问题,没有使用零停机部署插件。希望有人能够提供帮助,或者如果你解决了这个问题可以发布一个答案。也许可以联系Heroku支持团队? - Chris Peters
我注意到的是这通常发生在worker dynos上。并不总是,但通常如此。 - Chris Peters
这是Unicorn 4.6.3吗?你在4.6.2上试过吗? - Neil Middleton
这种情况在我的Heroku上也发生了。使用的是Unicorn 4.2.1,没有使用零停机插件。 - joseph.hainline
这篇帖子建议尝试使用Puma以获得潜在的成功:https://dev59.com/kmMm5IYBdhLWcg3wO9Hy - sdanzig
显示剩余6条评论
1个回答

4
我认为您定制的信号处理程序导致了这里的超时问题。
编辑:我因不同意Heroku的文档而被投诉,并且我想解决这个问题。
将Unicorn应用程序配置为捕获和忽略TERM信号是导致应用程序挂起并无法正确关闭的最可能原因。
Heroku似乎认为捕获和转换TERM信号为QUIT信号是将硬关闭变成优雅关闭的正确行为。
然而,这样做似乎会在某些情况下引入完全没有关闭的风险——这个错误的根源。正在经历Unicorn运行超时的用户应该考虑证据并基于第一原则做出自己的决策,而不仅仅是文档。

2
Heroku文档仍然涵盖“使用SIGTERM进行优雅关闭”,我没有看到不再需要在Cedar堆栈上执行此操作的提及。您是否有参考资料可以找到这个信息? - Dennis
我找不到任何支持这个答案的文档。根据Unicorn和Heroku的文档,Unicorn仍然使用POSIX信号解释的相反方式。 - Josh Kovach
这是不正确的。独角兽仍然不能在没有显式处理TERM信号的情况下正常关闭。支持此观点的Dev Center文章可以在此处找到:https://devcenter.heroku.com/articles/rails-unicorn#config - slant
我知道Heroku文档中提到你应该尝试捕获/转换这些信号。优雅地关闭尝试是关闭超时的最有可能的根本原因。 - Winfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接