こんにちは。Takitaです。
なぜかunicornのプロセスが死んでしまいサービスがエラーになるというケースがありました。
原因調査と並行してunicornのプロセスが死ぬと自動で立ち上げられるようにしました。
+gem 'god'
+RAILS_ENV = ENV['RAILS_ENV'] || 'production'
+RAILS_ROOT = ENV['RAILS_ROOT'] || '/var/www/app_name/current'
+
+God.watch do |w|
+ w.name = 'unicorn'
+ w.dir = RAILS_ROOT
+ w.interval = 30.seconds
+
+ w.start = "bundle exec unicorn -c #{RAILS_ROOT}/config/unicorn.rb -E #{RAILS_ENV} -D"
+ w.stop = "kill -s -QUIT `cat #{RAILS_ROOT}/tmp/pids/unicorn.pid`"
+ w.restart = "kill -s -USR2 `cat #{RAILS_ROOT}/tmp/pids/unicorn.pid`"
+
+ w.start_grace = 10.seconds
+ w.restart_grace = 10.seconds
+ w.pid_file = "#{RAILS_ROOT}/tmp/pids/unicorn.pid"
+ w.log = "#{RAILS_ROOT}/log/unicorn.god.log"
+
+ w.behavior(:clean_pid_file)
+
+ w.start_if do |start|
+ start.condition(:process_running) do |c|
+ c.interval = 5.seconds
+ c.running = false
+ end
+ end
+
+ # TODO: ひとまずprocessが死んだ時に再起動するだけにとどめたいのでコメントアウト
+ # w.restart_if do |restart|
+ # restart.condition(:cpu_usage) do |c|
+ # c.above = 80.percent
+ # c.times = 5
+ # end
+ # end
+
+ w.lifecycle do |on|
+ on.condition(:flapping) do |c|
+ c.to_state = %i[start restart]
+ c.times = 5
+ c.within = 5.minutes
+ c.transition = :unmonitored
+ c.retry_in = 10.minutes
+ c.retry_times = 5
+ c.retry_within = 2.hours
+ end
+ end
+end
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
- desc 'Restart application'
- task :restart do
- on roles(:app), in: :sequence, wait: 5 do
- invoke 'unicorn:legacy_restart'
- end
+ # ress: https://gist.github.com/jtomaszewski/8091945
+ def god_is_running
+ capture(:bundle, "exec god status > /dev/null 2>&1 || echo 'god not running'") != 'god not running'
end
- desc 'Create database'
- task :db_create do
- on roles(:app) do
- with rails_env: fetch(:rails_env) do
- within release_path do
- execute :bundle, :exec, :rake, 'db:create'
- end
- end
- end
+ def config_file
+ "#{current_path}/unicorn.god"
end
- after :publishing, :restart
+ def start_god
+ execute :bundle, "exec god -c #{config_file}"
+ end
- after :restart, :clear_cache do
- on roles(:web), in: :groups, limit: 3, wait: 10 do
+ desc "Restart god's child processes"
+ task :restart do
+ on roles(:app) do
+ within current_path do
+ with RAILS_ENV: fetch(:rails_env) do
+ if god_is_running
+ execute :bundle, "exec god load #{config_file}"
+ execute :bundle, 'exec god restart'
+ else
+ start_god
+ end
+ end
+ end
end
end
end
差分が見にくいので素のコードも貼っておきます。
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
# ress: https://gist.github.com/jtomaszewski/8091945
def god_is_running
capture(:bundle, "exec god status > /dev/null 2>&1 || echo 'god not running'") != 'god not running'
end
def config_file
"#{current_path}/unicorn.god"
end
def start_god
execute :bundle, "exec god -c #{config_file}"
end
desc "Restart god's child processes"
task :restart do
on roles(:app) do
within current_path do
with RAILS_ENV: fetch(:rails_env) do
if god_is_running
execute :bundle, "exec god load #{config_file}"
execute :bundle, 'exec god restart'
else
start_god
end
end
end
end
end
end
staging, productionともに以下の点を確認しました。
まず現在のunicornプロセスを見つけます。
$ ps aux | grep unicorn
ubuntu 5522 2.9 0.3 398832 31520 ? Sl 16:03 0:00 /var/www/app_name/shared/bundle/ruby/2.3.0/bin/god -c /var/www/app_name/current/unicorn.god
ubuntu 5551 80.6 2.6 1052516 218112 ? Sl 16:03 0:08 unicorn master -c /var/www/app_name/current/config/unicorn.rb -E production -D
ubuntu 5559 0.0 2.5 1052380 206624 ? Sl 16:03 0:00 unicorn worker[0] -c /var/www/app_name/current/config/unicorn.rb -E production -D
(省略)
$ kill -9 5522
をしてunicorn masterとworkderのプロセスをkillします。
すると以下のようにgodのプロセスだけ残り、unicornのプロセスはすべて落ちたことがわかります。
(topコマンドとかでもいいですが)
$ ps aux | grep unico
ubuntu 5522 1.4 0.3 398832 31520 ? Sl 16:03 0:00 /var/www/app_name/shared/bundle/ruby/2.3.0/bin/god -c /var/www/app_name/current/unicorn.god
ubuntu 5610 0.0 0.0 10460 932 pts/0 S+ 16:04 0:00 grep --color=auto unico
数十秒経つとunicornのプロセスが立ち上がります。
godのプロセスが立ち上がっている状態でデプロイするとgodプロセスが複数立ち上がってしまったような気がしたので(少し前に対応したのであまり覚えてない)、
連続したデプロイでもプロセスが期待通りかどうかを念のため確認しておきました。
今回は以前少し触ったことがあるGodを採用しましたが、Monitも機会があれば触ってみたいなと思います。
投稿が古かったりしますが、以下が非常に参考になりました。
https://gist.github.com/jtomaszewski/8091945
http://d.hatena.ne.jp/nekonokataomoi/20140214