2011-12-29 1 views
9

Хорошо, это тает мой мозг. Возможно, это связано с тем, что я не понимаю Upstart так же хорошо, как и должен. Извините заранее за длинный вопрос.Использование Upstart для управления Unicorn w/rbenv + bundler binstubs w/ruby-local-exec shebang

Я пытаюсь использовать Upstart для управления процессом Unicorn для Rails. Вот мой текущий /etc/init/app.conf:

description "app" 

start on runlevel [2] 
stop on runlevel [016] 

console owner 

# expect daemon 

script 
    APP_ROOT=/home/deploy/app 
    PATH=/home/deploy/.rbenv/shims:/home/deploy/.rbenv/bin:$PATH 
    $APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production # >> /tmp/upstart.log 2>&1 
end script 

# respawn 

Это работает просто прекрасно - единороги запустить большой. Что не удивительно, так это то, что обнаруженный ПИД не является мастером Единорога, а процессом sh. Это само по себе не так уж плохо, если бы я не использовал автоматическую стратегию развертывания без потерь в Unicorn. Потому что вскоре после того, как я отправлю -USR2 моему мастеру Единорога, новый мастер появляется, а старый умирает ... и так же работает sh. Поэтому Upstart считает, что моя работа скончалась, и я больше не могу ее перезапускать restart или остановить ее с помощью stop, если захочу.

Я играл с файлом конфигурация, пытаясь добавить -D к Unicorn линии (как это: $APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production -D) к демону Unicorn, и я добавил expect daemon линии, но это не сработало. Я тоже пробовал expect fork. Различные комбинации всех этих вещей могут привести к зависанию start и stop, а затем Upstart действительно запутается в состоянии задания. Затем я должен перезапустить машину, чтобы исправить ее.

Я думаю, что у Upstart возникают проблемы с обнаружением, когда/если единорог разветвляется, потому что я использую rbenv + ruby-local-exec shebang в моем сценарии $APP_ROOT/bin/unicorn. Вот оно:

#!/usr/bin/env ruby-local-exec 
# 
# This file was generated by Bundler. 
# 
# The application 'unicorn' is installed as part of a gem, and 
# this file is here to facilitate running it. 
# 

require 'pathname' 
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 
    Pathname.new(__FILE__).realpath) 

require 'rubygems' 
require 'bundler/setup' 

load Gem.bin_path('unicorn', 'unicorn') 

Кроме того, ruby-local-exec сценарий выглядит следующим образом:

#!/usr/bin/env bash 
# 
# `ruby-local-exec` is a drop-in replacement for the standard Ruby 
# shebang line: 
# 
# #!/usr/bin/env ruby-local-exec 
# 
# Use it for scripts inside a project with an `.rbenv-version` 
# file. When you run the scripts, they'll use the project-specified 
# Ruby version, regardless of what directory they're run from. Useful 
# for e.g. running project tasks in cron scripts without needing to 
# `cd` into the project first. 

set -e 
export RBENV_DIR="${1%/*}" 
exec ruby "[email protected]" 

Так что в exec там, что я беспокоюсь о. Он запускает процесс Ruby, который запускает Unicorn, который может или не может быть демонизирован, что происходит сначала из процесса sh ... что заставляет меня серьезно сомневаться в способности Upstart отслеживать всю эту глупость.

Является ли то, что я пытаюсь сделать, даже возможно? Насколько я понимаю, строфу expect в Upstart можно сообщить только (через daemon или fork), чтобы ожидать максимум две вилки.

ответ

15

Ваша задача выскочки должна быть настроена так, чтобы выскочка точно знала, сколько раз она вилки. И он может только развиваться один или два раза, не более того.

В стране Unix есть два ключевых системных вызова, которые облегчают запуск программ: fork и exec.

fork копирует процесс, который его вызывает. Один процесс вызывает fork, и он возвращает управление обратно двум процессам. Каждый процесс должен определить, какой он (родительский или дочерний), из значения, возвращаемого fork (подробности см. На странице руководства).

exec запускает новую программу, заменяя процесс, который называется exec.

Когда вы просто запустить команду в оболочке, то под капотом оболочка вызывает fork, чтобы создать новый процесс со своим собственным идентификатором, и этот новый процесс (после некоторой настройки) немедленно вызывает exec запустить команду вы набрали , Так выполняется большинство программ, будь то оболочка или ваш оконный менеджер или что-то еще. См. Функцию system в C, которая также имеет варианты на большинстве языков сценариев.

Если вы считаете, что это неэффективно, вы, вероятно, правы. Как это было сделано в unix с самых долгих лет, и совершенно очевидно, что ни одна игра не изменит его. Одна из причин заключается в том, что существует много вещей, которые не заменены на exec, включая (иногда) открытые файлы и идентификаторы пользователя и группы процесса.

Другая причина заключается в том, что много усилий было потрачено сделать fork эффективным, и они на самом деле сделали очень хорошую работу по ним - в современных Unixes (с помощью CPU) fork фактически копирует очень мало процесса , Наверное, никто не хочет бросить все эти работы.

И, (пауза для эффекта) процессы pid.

Чтобы продемонстрировать:

[email protected]:~$ echo $$ 
3652 
[email protected]:~$ bash 
[email protected]:~$ echo $$ 
6545 
[email protected]:~$ exec bash 
[email protected]:~$ echo $$ 
6545 
[email protected]:~$ exit 
exit 
[email protected]:~$ echo $$ 
3652 

Большинство популярных языков имеют вариации вилке и EXEC, в том числе оболочки, C, Perl, рубин и питона. Но не ява.

Так что, имея в виду, что вам нужно сделать, чтобы ваша работа над выскочкой работала, убедитесь, что она вилки того же количества раз, что и выскочка.

exec линия в ruby-local-exec на самом деле хорошая вещь, она предотвращает развитие вилки. Также load не запускает новый процесс, он просто загружает код в существующий рубиновый интерпретатор и запускает его.

Однако ваши оболочки вилки сценарий в этой строке:

$APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production # >> /tmp/upstart.log 2>&1 

, чтобы предотвратить это, вы можете просто изменить его на

exec $APP_ROOT/bin/unicorn -c $APP_ROOT/config/unicorn.rb -E production # >> /tmp/upstart.log 2>&1 

Если вы сделаете это, AFAICT единорог не должен раскошелиться на всех, и вам не нужно будет говорить выскочку, ожидая развилки.

+0

Удивительно, спасибо за это. – codykrieger

+0

Спасибо за подробный ответ! Это просто помогло мне установить Бога + Upstart в идентичной ситуации. – dreikanter