ruby - ¿Cómo puedo decirle al unicornio que entienda las señales de Heroku?
heroku dashboard login (2)
Tal vez has visto esto ...
2012-03-07T15:36:25+00:00 heroku[web.1]: Stopping process with SIGTERM 2012-03-07T15:36:36+00:00 heroku[web.1]: Stopping process with SIGKILL 2012-03-07T15:36:36+00:00 heroku[web.1]: Error R12 (Exit timeout) -> Process failed to exit within 10 seconds of SIGTERM 2012-03-07T15:36:38+00:00 heroku[web.1]: Process exited with status 137
Este es un problema bien conocido cuando se ejecuta unicornio en heroku ...
¿Puedo decirle a heroku que envíe SIGQUIT
? ¿O puedo decirle a unicornio que trate a SIGTERM
como un elegante cierre?
Esto es un truco, pero he creado con éxito un archivo de configuración de unicornio que atrapa la señal TERM
, lo que impide que el unicornio lo reciba y realice su apagado rápido. Mi manejador de señal luego envía la señal QUIT
regreso a sí mismo para activar el apagado elegante del unicornio.
Probado con Ruby 1.9.2, Unicorn 4.0.1 y 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
Una preocupación es que (creo) este manejador de señal es heredado por procesos de trabajo. Sin embargo, el proceso de trabajo instala su propio controlador TERM
, que debe sobrescribir este, por lo que no esperaría ningún problema. (Ver Unicorn::HttpServer#init_worker_process @ lib/unicorn/http_server.rb:551
.
Editar: un detalle más, este bloque que instala el controlador de señal se ejecutará una vez por proceso de trabajo (porque before_fork
), pero esto simplemente redundante y no afectará nada.
Heroku ahora proporciona instrucciones para esto aquí: https://blog.heroku.com/archives/2013/2/27/unicorn_rails
Su sugerencia de archivo unicorn.rb es:
# 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