捕获 TERM 并发送 QUIT 后 Heroku 上的独角兽退出超时

Posted

技术标签:

【中文标题】捕获 TERM 并发送 QUIT 后 Heroku 上的独角兽退出超时【英文标题】:Unicorn exit timeout on Heroku after trapping TERM and sending QUIT 【发布时间】:2013-07-01 07:19:01 【问题描述】:

我收到运行 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

似乎所有子进程在超时之前都已成功收割。有没有可能师父还活着?此外,路由器在关闭期间是否仍向测功机发送 Web 请求,如日志中所示?

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

【问题讨论】:

如果有帮助,我也遇到了这个问题没有零停机时间部署插件。我希望有人可以提供帮助,或者如果您弄清楚了,您可以发布答案。也许联系 Heroku 支持? 就像克里斯一样,我没有使用零停机时间,并且遇到了这个问题。尽管使用了 Heroku 推荐的独角兽配置。 我遇到了同样的问题,尽管使用了 Heroku 推荐的配置。也没有零停机部署。 同样的问题,并且没有使用预启动插件。 我注意到的一件事是,这通常发生在工人测功机上。不总是,但通常。 【参考方案1】:

我认为您的自定义信号处理是导致这里超时的原因。

编辑:我因不同意 Heroku 的文档而被否决,我想解决这个问题。

将您的 Unicorn 应用程序配置为捕获并吞下 TERM 信号是导致您的应用程序挂起和无法正确关闭的最可能原因。

Heroku 似乎认为捕获 TERM 信号并将其转换为 QUIT 信号是将硬关机转换为正常关机的正确行为。

但是,在某些情况下,这样做似乎会带来根本不关机的风险——这是这个错误的根源。遇到运行 Unicorn 的悬挂式测功机的用户应考虑证据并根据第一原则做出自己的决定,而不仅仅是文档。

【讨论】:

Heroku 文档仍然涵盖“Graceful shutdown with SIGTERM”,我没有看到在 Cedar 堆栈上不再需要这样做的提及。你有参考在哪里可以找到吗? 我找不到任何支持此答案的文档。根据 Unicorn 和 Heroku 的文档,Unicorn 仍然使用相反的 POSIX 信号解释。 这不是真的。如果没有明确处理 TERM 信号,Unicorn 仍然不会正常关闭。支持这一点的开发中心文章可以在这里找到:devcenter.heroku.com/articles/rails-unicorn#config 我知道 Heroku 文档说您应该尝试捕获/转换这些信号。正常关机的尝试是关机超时最可能的根本原因。

以上是关于捕获 TERM 并发送 QUIT 后 Heroku 上的独角兽退出超时的主要内容,如果未能解决你的问题,请参考以下文章

未捕获的错误:无法将 WP_Term 类型的对象用作数组

部署Django+React到Heroku - 未捕获的语法错误。意外的标记'<'

linux kill命令

使用 Heroku 构建可扩展分析后端的最佳方法是啥? [关闭]

Golang信号处理和优雅退出守护进程

不使用 Mandrill 发送电子邮件的问题 -> 部署到 Heroku