Перезапустить Единорог с USR2 - покинуть старый мастер
Поэтому отправка USR2 в Unicorn - это потрясающе - он запускает нового мастера с новой копией вашего кода и автоматически получает любые изменения. Милая. Мой вопрос: как остановить старого мастера? По-видимому, принятый способ находится в файле before_fork:
before_fork do |server,worker|
old_pid = '/var/www/current/tmp/pids/unicorn.pid.oldbin'
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
Проблема заключается в том, что как только новый мастер (и новые рабочие) порождается, они убивают старого мастера. Поэтому любые запросы на сайт просто сидят там, ожидая, когда новый рабочий начнет работу, обычно в течение нескольких секунд, пока загружается весь столбец Rails.
Если я удалю свой файл before_fork, все будет работать так, как я надеюсь (с точки зрения клиента): я могу перезагрузить мой браузер весь день, и каждый запрос заполняется быстро, нет никаких указаний о том, когда новый хозяин берет верх (кроме видя, что теперь появляются изменения кода). Но, старый мастер теперь висит, пока я вручную не отправлю его QUIT.
Насколько я знаю, нет обратного вызова после того, как работник будет загружен и готов обслуживать клиентов. Это действительно обратный вызов, который я ищу. Я всегда мог создать инициализатор в Rails, который ищет старого хозяина и убивает его, но это заставляет мое сердце болеть, просто думая об этом.
Должен быть способ!
Ответы
Ответ 1
Я частично решил это: поведение, которое я вижу, вызвано не использованием preload_app true
. Если у вас есть этот набор, все приложение загружается мастером, и рабочие очень быстро появляются. Поэтому, если первый работник убивает старого хозяина в этот момент, все в порядке, потому что упомянутый рабочий может немедленно начать подавать запросы!
Если вы не можете использовать preload_app true
, то лучше всего переместить это поведение old-pid-quit в инициализатор Rails, чтобы первый работник, открывший ваше приложение, мог убить старого мастера после запуска Rails и готов к выполнению запросов.
Ответ 2
Похоже, что отправка HUP-сигнала в Master Unicorn является лучшей альтернативой, если preload_app
- false
.
Из http://unicorn.bogomips.org/SIGNALS.html:
HUP - перезагружает конфигурационный файл и изящно перезапустить всех работников. Если Директива preload_app - false ( по умолчанию), тогда работники также изменение любого кода приложения, когда перезапущен.
Ответ 3
Вот что у меня в моем блоке before_fork:
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
end
end
Чтобы перезапустить мой единорог, у меня есть bash script, у которого есть такой способ:
if sig USR2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
bash script отправляет сигнал USR2, который открывает новый единорог и создает старый pid. Затем он отправляет старому единорогу сигнал QUIT с помощью старого pid.
Этот процесс работает очень хорошо и был взят из Где единороги умирают: Наблюдая за единорогами с monit, это отличный ресурс.