I just switched to deploy my Rails project on unicorn. In my capistrano recipe deploy:restart
is
task :restart, :except => { :no_release => true } do
run "cd #{shared_path}/pids && kill -s USR2 `cat unicorn.pid`"
end
But from time to time I found that, sometimes the deploy procedure finished with success, but although the unicorn.pid is updated, the unicorn processes remains still.
For example, I deployed at Dec.15th, and I monitored that unicorn.pid
is updated, but if I run ps -ef | grep unicorn
, I could see that the unicorn process is still started at the time of my last deployment, so it refers to the last release folder which causes trouble.
Why is that?
The following is my unicorn.rb
file:
env = ENV["RAILS_ENV"]
case env
when 'pre', 'production'
@app_path = '/home/deployer/deploy/myproject'
end
if env == 'pre' || env == 'production'
user 'deployer', 'staff'
shared_path = "#{@app_path}/shared"
stderr_path "#{shared_path}/log/unicorn.stderr.log"
stdout_path "#{shared_path}/log/unicorn.stdout.log"
if env == 'production'
worker_processes 6
else
worker_processes 2
end
working_directory "#{@app_path}/current" # available in 0.94.0+
listen "/tmp/myproject.sock", :backlog => 64
timeout 30
pid "#{shared_path}/pids/unicorn.pid"
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
before_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
old_pid = "#{shared_path}/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
after_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
end
I'm not sure why this is the case, but personally I don't kill the Unicorn PID when deploying via Capistrano.
Rather, I start unicorn via the god gem, and configure the god file so it restarts unicorn whenever a file has been touched.
When I deploy via Capistrano, I then touch the file after every deploy, forcing the unicorn process to restart
namespace :deploy do
desc "Touch restart.txt, which will restart all God processes"
task :restart do
run "touch #{ current_path }/tmp/restart.txt"
end
You need to add this module to the .god file too:
module God
module Conditions
class RestartFileTouched < PollCondition
attr_accessor :restart_file
def initialize
super
end
def process_start_time
Time.parse(`ps -o lstart -p #{self.watch.pid}`)
end
def restart_file_modification_time
File.mtime(self.restart_file)
end
def valid?
valid = true
valid &= complain("Attribute 'restart_file' must be specified", self) if self.restart_file.nil?
valid
end
def test
process_start_time < restart_file_modification_time
end
end
end
end