我该如何告诉独角兽理解Heroku的信号?

9

也许你见过这个问题...

2012-03-07T15:36:25+00:00 heroku[web.1]: 使用SIGTERM停止进程
2012-03-07T15:36:36+00:00 heroku[web.1]: 使用SIGKILL停止进程
2012-03-07T15:36:36+00:00 heroku[web.1]: 错误R12(退出超时) -> 进程在SIGTERM信号后的10秒内未能退出
2012-03-07T15:36:38+00:00 heroku[web.1]: 进程以状态137退出

heroku上运行unicorn时,这是一个众所周知的问题...

我可以告诉heroku发送SIGQUIT吗?或者我可以告诉unicorn将SIGTERM视为优雅关闭吗?


我之前不知道这个。我正在考虑在一个项目中使用Unicorn,但是这让我重新考虑了。这里是Thin使用的信号:https://github.com/macournoyer/thin/blob/master/lib/thin/server.rb#L211 在两种情况下,QUIT信号表示优雅的关闭,但是INT和TERM被交换了。 - John Bachir
1
顺便提一下,这里还有另一个因素——Heroku会向Procfile中定义的进程发送TERM信号,但是该进程负责根据自己的情况传递信号。因此,即使Heroku发送了正确的信号,如果你在bundle exec后面运行服务器,你仍然会看到上述行为,因为Web服务器根本没有收到信号。我已经与支持团队讨论过这个问题,他们正在想办法解决。 - John Bachir
2
我今天发现了这个,但我还没有探索它:https://github.com/ddollar/foreman/wiki/Custom-Signals - John Bachir
2个回答

9

Heroku现在提供了相应的说明,可以在这里查看:https://blog.heroku.com/archives/2013/2/27/unicorn_rails

他们建议使用的unicorn.rb文件如下:

# config/unicorn.rb
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'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|

  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

7

这是一个技巧,但我已经成功创建了一个独角兽配置文件,可以捕获 TERM 信号,防止独角兽接收并快速关闭。然后我的信号处理程序会回发 QUIT 信号给自身,以触发独角兽优雅的关闭。

在 Ruby 1.9.2、Unicorn 4.0.1 和 4.2.1、Mac OS X 上测试过。

listen 9292
worker_processes 1

# This is a hack.  The code is run with 'before_fork' so it runs
# *after* Unicorn installs its own TERM signal handler (which makes
# this highly dependent on the Unicorn implementation details).
#
# We install our own signal handler for TERM and simply re-send a QUIT
# signal to our self.
before_fork do |_server, _worker|
  Signal.trap 'TERM' do
    puts 'intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end
end

一个担忧是(我认为)这个信号处理程序会被工作进程继承。但是,工作进程会安装自己的TERM处理程序,应该会覆盖这个处理程序,所以我不会预料到任何问题。(请参见Unicorn::HttpServer#init_worker_process @ lib/unicorn/http_server.rb:551)。

编辑:还有一个细节,安装信号处理程序的这个块将每个工作进程运行一次(因为before_fork),但这只是多余的,不会影响任何事情。


2
这是被接受的答案,因为Patrick在Heroku之前就想出来了...但是请查看Clay的答案以获取最新的权威答案。 - Seamus Abshere

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