Запуск или перезапуск Unicorn с Capistrano 3.x

Я пытаюсь запустить или перезапустить Unicorn, когда я делаю cap production deploy с Capistrano 3.0.1. У меня есть несколько примеров того, что я работал с Capistrano 2.x, используя что-то вроде:

namespace :unicorn do
  desc "Start unicorn for this application"
  task :start do
    run "cd #{current_path} && bundle exec unicorn -c /etc/unicorn/myapp.conf.rb -D"
  end
end

Но когда я пытаюсь использовать run в deploy.rb для Capistrano 3.x, я получаю ошибку метода undefined.

Вот несколько вещей, которые я пробовал:

# within the :deploy I created a task that I called after :finished
namespace :deploy do
...

  task :unicorn do
    run "cd #{current_path} && bundle exec unicorn -c /etc/unicorn/myapp.conf.rb -D"
  end

  after :finished, 'deploy:unicorn'

end

Я также попытался поместить запуск в задачу: restart

namespace :deploy do
  desc 'Restart application'
  task :restart do

  on roles(:app), in: :sequence, wait: 5 do
    # Your restart mechanism here, for example:
    # execute :touch, release_path.join('tmp/restart.txt')
    execute :run, "cd #{current_path} && bundle exec unicorn -c /etc/unicorn/deployrails.conf.rb -D"
  end
end    

Если я использую только run "cd ... " then I'll get a неправильное количество аргументов (1 для 0) `в локальной оболочке.

Я могу запустить процесс единорога с помощью unicorn -c /etc/unicorn/deployrails.conf.rb -D из моей оболочки ssh'd VM.

Я могу убить главный процесс Unicorn из оболочки VM, используя kill USR2, но даже при том, что процесс убит, я получаю сообщение об ошибке. Затем я могу начать процесс снова, используя unicorn -c ...

$ kill USR2 58798
bash: kill: USR2: arguments must be process or job IDs

Я очень новичок в Ruby, Rails и Deployment в целом. У меня есть установка VirtualBox с Ubuntu, Nginx, RVM и Unicorn, я до сих пор очень рад, но этот действительно возится со мной, любые советы или проницательность оценены.

Ответ 1

Не могу сказать ничего конкретного о capistrano 3 (я использую 2), но я думаю, что это может помочь: Как запустить команды оболочки на сервере в Capistrano v3?, Также я могу поделиться опытом, связанным с единорогом, надеюсь, что это поможет.

Я предполагаю, что вы хотите 24/7 изящный подход к перезапуску.

Проконсультируйтесь с документацией единорога. Для изящного перезапуска (без простоя) вы можете использовать две стратегии:

  • kill -HUP unicorn_master_pid Это требует, чтобы ваше приложение отключило директиву preload_app, увеличив время начала работы каждого из единорогов. Если вы можете жить с этим - продолжайте, это ваш звонок.

  • kill -USR2 unicorn_master_pid kill -QUIT unicorn_master_pid

Более сложный подход, когда вы уже имеете дело с проблемами производительности. В основном он будет повторно выполнять мастер-процесс единорога, тогда вы должны убить его предшественника. Теоретически вы можете иметь дело с usr2-sleep-quit. Другой (и, я могу сказать, правильный вариант) - использовать unicorn before_fork hook, он будет выполнен, когда новый мастер-процесс будет порожден и будет пытаться для новых детей для себя. Вы можете поместить что-то подобное в config/unicorn.rb:

# Where to drop a pidfile
pid project_home + '/tmp/pids/unicorn.pid'

before_fork do |server, worker|
  server.logger.info("worker=#{worker.nr} spawning in #{Dir.pwd}")

  # graceful shutdown.
  old_pid_file = project_home + '/tmp/pids/unicorn.pid.oldbin'
  if File.exists?(old_pid_file) && server.pid != old_pid_file
    begin
      old_pid = File.read(old_pid_file).to_i
      server.logger.info("sending QUIT to #{old_pid}")
      # we're killing old unicorn master right there
      Process.kill("QUIT", old_pid)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

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

И еще одна вещь - вы можете поставить ее под runit или init superv. Таким образом, ваши задачи capistrano будут такими же простыми, как sv reload unicorn, restart unicorn или /etc/init.d/unicorn restart. Это хорошо.

Ответ 2

Я использую следующий код:

namespace :unicorn do
  desc 'Stop Unicorn'
  task :stop do
    on roles(:app) do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        execute :kill, capture(:cat, fetch(:unicorn_pid))
      end
    end
  end

  desc 'Start Unicorn'
  task :start do
    on roles(:app) do
      within current_path do
        with rails_env: fetch(:rails_env) do
          execute :bundle, "exec unicorn -c #{fetch(:unicorn_config)} -D"
        end
      end
    end
  end

  desc 'Reload Unicorn without killing master process'
  task :reload do
    on roles(:app) do
      if test("[ -f #{fetch(:unicorn_pid)} ]")
        execute :kill, '-s USR2', capture(:cat, fetch(:unicorn_pid))
      else
        error 'Unicorn process not running'
      end
    end
  end

  desc 'Restart Unicorn'
  task :restart
  before :restart, :stop
  before :restart, :start
end

Ответ 3

Я просто собираюсь бросить это на ринг: capistrano 3 unicorn gem

Однако моя проблема с камнем (и любым подходом, не использующим init.d script), заключается в том, что теперь у вас может быть два метода управления процессом единорога. Один с этой задачей и один с init.d скриптами. Такие вещи, как Монит/Бог, будут запутаны, и вы можете потратить несколько часов на отладку, почему у вас есть два процесса единорога, которые пытаются начать, а затем вы можете начать ненавидеть жизнь.

В настоящее время я использую следующее с capistrano 3 и единорогом:

  namespace :unicorn do
  desc 'Restart application'
    task :restart do
      on roles(:app) do
        puts "restarting unicorn..."
        execute "sudo /etc/init.d/unicorn_#{fetch(:application)} restart"
        sleep 5
        puts "whats running now, eh unicorn?"
        execute "ps aux | grep unicorn"
      end
    end
end

Вышеуказанное сочетается с предзагрузками preload_app: true и before_fork и after_fork, упомянутыми @dredozubov

Примечание. Я назвал имя init.d/unicorn script unicorn_application_name.

Новый рабочий, который запускается, должен убить старый. Вы можете видеть с помощью ps aux | grep unicorn, что старый мастер висит вокруг в течение нескольких секунд, прежде чем он исчезнет.

Ответ 4

Вы можете попробовать использовать собственный capistrano способ, как написано здесь:

Если preload_app: true, и вам нужно capistrano для очистки вашего oldbin pid, используйте:

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:legacy_restart'
  end
end