I'm using capistrano in my rails4 app and everytime I'm release a new version (=> cap production deploy
) I need to kill the unicorn master on the server so that the capistrano can walk without any failures.
### How can I automate the process of killing the unicorn process?
This is how my deploy.rb is looking like:
lock '3.4.0'
set :application, 'maalify'
set :repo_url, '[email protected]:iNeedCode/Maalify.git'
set :deploy_to, '/opt/www/maalify'
set :user, 'root'
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets}
set :rbenv_ruby, '2.2.1'
set :rbenv_type, :user
set :rbenv_path, "~/.rbenv"
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w(rake gem bundle ruby rails)
set :rbenv_roles, :all
set :linked_files, %w{config/database.yml .rbenv-vars} # create these files manually ones on the server
# Capristrano3 unicorn
set :unicorn_pid, "/opt/www/maalify/current/shared/tmp/pids/unicorn.pid"
set :unicorn_config_path, "/opt/www/maalify/current/config/unicorn.rb"
# Clean up all older releases
before :deploy, "unicorn:stop"
after "deploy:publishing", "unicorn:start"
after "deploy:restart", "deploy:cleanup"
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
execute :rake, 'cache:clear'
end
end
end
Here is the Unicorn.rb
# set path to application
app_dir = "/opt/www/maalify"
shared_dir = "#{app_dir}/shared"
working_directory "#{app_dir}/current"
# Set unicorn options
worker_processes 1
preload_app true
timeout 30
# Set up socket location
listen "#{shared_dir}/tmp/sockets/unicorn.sock", :backlog => 64
# Logging
stderr_path "#{shared_dir}/log/unicorn.stderr.log"
stdout_path "#{shared_dir}/log/unicorn.stdout.log"
# Set master PID location
pid "#{shared_dir}/tmp/pids/unicorn.pid"
After adding the before_fork
I'm still getting the same error as previously when I didn't kill unicorn by hand:
/opt/www/maalify/shared/bundle/ruby/2.2.0/gems/unicorn-4.8.3/lib/unicorn/http_server.rb:206:in `pid=': Already running on PID:16268 (or pid=/opt/www/maalify/shared/tmp/pids/unicorn.pid is stale) (ArgumentError)
from /opt/www/maalify/shared/bundle/ruby/2.2.0/gems/unicorn-4.8.3/lib/unicorn/http_server.rb:135:in `start'
from /opt/www/maalify/shared/bundle/ruby/2.2.0/gems/unicorn-4.8.3/bin/unicorn:126:in `<top (required)>'
from /opt/www/maalify/shared/bundle/ruby/2.2.0/bin/unicorn:23:in `load'
from /opt/www/maalify/shared/bundle/ruby/2.2.0/bin/unicorn:23:in `<main>'
I've noticed in your unicorn config file next directive:
preload_app true
Here is info from docs:
HUP - reloads config file and gracefully restart all workers. If the "preload_app" directive is false (the default), then workers will also pick up any application code changes when restarted. If "preload_app" is true, then application code changes will have no effect; USR2 + QUIT (see below) must be used to load newer code in this case.
You can set directive preload_app
to false and then if you need to reload code, send HUP
signal to master process.
But here is another way to reload code without downtime. You need to implement USR2 + QUIT
method in config. It means when you send USR2
signal, unicorn starts new instance of application without killing old one. You can hook before_fork
callback to which will kill old instance painless for you.
Here is example, add this to unicorn config:
before_fork do |server, worker|
ActiveRecord::Base.connection.disconnect!
old_pid = "#{server.config[: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
after_fork do |server, worker|
ActiveRecord::Base.establish_connection
end
Now send USR2 signal to master process and check it out!
Next step is change your deploy.rb. You need to remove all unicorn
hooks and add next one:
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:legacy_restart'
end
end
And last step: fix pid path in deploy.rb.
set :unicorn_pid, "/opt/www/maalify**/current/shared/**tmp/pids/unicorn.pid"
Must be:
set :unicorn_pid, "/opt/www/maalify/shared/tmp/pids/unicorn.pid"