Хорошо, это плавит мой мозг. Возможно, это связано с тем, что я не так хорошо понимаю Upstart, как следовало бы. Заранее извините за длинный вопрос.
Я пытаюсь использовать Upstart для управления процессом Unicorn master в приложении 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
Это работает просто отлично - единороги запускаются отлично. Что не очень хорошо, так это то, что обнаруженный PID принадлежит не мастеру Unicorn, а процессу sh
. Само по себе это тоже не так уж плохо - если бы я не использовал автоматическую стратегию развертывания Unicorn с нулевым временем простоя. Потому что вскоре после того, как я отправил -USR2
моему мастеру Unicorn, появляется новый мастер, а старый умирает... и процесс 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 проблемы с определением того, когда/если Unicorn форкается, потому что я использую 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 "$@"
Итак, там есть exec
, который меня беспокоит. Он запускает процесс Ruby, который запускает Unicorn, который может или не может демонизировать себя, и все это происходит из процесса sh
в первую очередь... что заставляет меня серьезно сомневаться в способности Upstart отслеживать всю эту ерунду.
Возможно ли вообще то, что я пытаюсь сделать? Насколько я понимаю, строфа expect
в Upstart может быть указана (через daemon
или fork
) только для ожидания максимум двух форков.