Перезапустите Единорога с USR2 - выход из старого мастера - PullRequest
22 голосов
/ 26 апреля 2011

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

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

Ответы [ 3 ]

16 голосов
/ 26 апреля 2011

Я частично решил это: поведение, которое я вижу, вызвано неиспользованием preload_app true. Если у вас есть этот набор, то все приложение загружается мастером, и рабочие очень быстро появляются. Поэтому, если первый работник убивает старого мастера в этот момент, это нормально, потому что указанный работник может немедленно начать обслуживать запросы!

Если вы не можете использовать preload_app true, тогда вам лучше всего перенести это поведение old-pid-quit в инициализатор Rails, чтобы первый работник, который запускает ваше приложение, мог убить старого мастера после запуска Rails. и готов обслуживать запросы.

8 голосов
/ 24 мая 2011

Похоже, что отправка сигнала HUP ведущему Unicorn является лучшей альтернативой, если preload_app равно false.

С http://unicorn.bogomips.org/SIGNALS.html:

HUP - перезагружает файл конфигурации и корректно перезапускает всех рабочих.Если директива preload_app имеет значение false (по умолчанию), то при перезапуске работники также поймут любые изменения кода приложения.

3 голосов
/ 28 мая 2011

Вот что у меня в блоке 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, который имеет такой метод:

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 отправляет сигнал USR2, который разветвляет нового единорога и создает старый pid. Затем он отправляет старому единорогу сигнал QUIT, используя старый pid.

Этот процесс работает очень хорошо и был взят из Куда умирают Единороги: Наблюдение за рабочими единорогов с monit , который является отличным ресурсом.

...