Подтвердить что ты не робот

Перезапустить Единорог с 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, который ищет старого хозяина и убивает его, но это заставляет мое сердце болеть, просто думая об этом.

Должен быть способ!

4b9b3361

Ответ 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, это отличный ресурс.