検索すると沢山でてきて、困らないのですが、
もっと運用しやすいようにログ出したり、エラーハンドリングしたり、作り込んでみました。
Unicornインストール
Gemfile に追加
# Use Unicorn gem 'unicorn'
$ bundle install
Unicorn設定
デフォルトを定数で定義しつつ、環境変数があればそっちを優先するようにしました。
また、どの設定が使われているかも標準出力。unicorn_stdout.logにも出力されますね。
あと、エラーハンドリングも。
config/unicorn.rb を作成
最新のコードこちら → https://dev.azure.com/nightonly/_git/rails-app-origin?path=/config/unicorn.rb&version=GBdevelop
unless defined?(DEFAULT_WORKER_PROCESSES)
DEFAULT_WORKER_PROCESSES = 2
DEFAULT_TIMEOUT = 60
DEFAULT_LISTEN = File.expand_path('../tmp/sockets/unicorn.sock', __dir__).freeze
DEFAULT_PID_PATH = File.expand_path('../tmp/pids/unicorn.pid', __dir__).freeze
DEFAULT_STDERR_PATH = File.expand_path('../log/unicorn_stderr.log', __dir__).freeze
DEFAULT_STDOUT_PATH = File.expand_path('../log/unicorn_stdout.log', __dir__).freeze
end
p "RAILS_ENV: #{ENV['RAILS_ENV'] || 'development(default)'}"
p "WORKER_PROCESSES: #{ENV['WORKER_PROCESSES'] || "#{DEFAULT_WORKER_PROCESSES}(default)"}"
p "TIMEOUT: #{ENV['TIMEOUT'] || "#{DEFAULT_TIMEOUT}(default)"}"
p "LISTEN: #{ENV['LISTEN'] || "#{DEFAULT_LISTEN}(default)"}"
pid_path = ENV['PID_PATH'] || DEFAULT_PID_PATH
p "PID_PATH: #{ENV['PID_PATH'] || "#{DEFAULT_PID_PATH}(default)"}[#{File.exist?(pid_path) ? File.read(pid_path).to_i : 'Not found'}]"
p "STDERR_PATH: #{ENV['STDERR_PATH'] || "#{DEFAULT_STDERR_PATH}(default)"}"
p "STDOUT_PATH: #{ENV['STDOUT_PATH'] || "#{DEFAULT_STDOUT_PATH}(default)"}"
worker_processes Integer(ENV['WORKER_PROCESSES'] || DEFAULT_WORKER_PROCESSES)
timeout Integer(ENV['TIMEOUT'] || DEFAULT_TIMEOUT)
preload_app true
listen ENV['LISTEN'] || DEFAULT_LISTEN
pid pid_path
stderr_path ENV['STDERR_PATH'] || DEFAULT_STDERR_PATH
stdout_path ENV['STDOUT_PATH'] || DEFAULT_STDOUT_PATH
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{server.config[:pid]}.oldbin"
if (old_pid != server.pid) && File.exist?(old_pid)
begin
signal = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(signal, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH => e
p e
end
end
end
after_fork do |_server, _worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
タスク作成
作らなくても、コマンド打てばできますが、
タスク作って、エラーハンドリングもしておくと運用時に楽なので作成しました。
lib/tasks/unicorn.rake を作成
最新のコードこちら → https://dev.azure.com/nightonly/_git/rails-app-origin?path=/lib/tasks/unicorn.rake&version=GBdevelop
namespace :unicorn do
DEFAULT_PID_PATH = File.expand_path('../../tmp/pids/unicorn.pid', __dir__).freeze
desc 'Unicorn起動(bundle exec unicorn)'
task(:start) do
pid_path = ENV['PID_PATH'] || DEFAULT_PID_PATH
if File.exist?(pid_path)
p "Found: #{pid_path}"
exit 1
end
rails_env = ENV['RAILS_ENV'] || 'development'
sh "bundle exec unicorn -c config/unicorn.rb -D -E #{rails_env}"
end
desc 'Unicorn停止(QUIT)'
task(:stop) { process_kill(:QUIT) }
desc 'Unicorn再起動(HUP)'
task(:restart) { process_kill(:HUP) }
desc 'Unicorn緩やかな再起動(USR2)'
task(:graceful) { process_kill(:USR2) }
desc 'Unicornのワーカープロセスを増やす(TTIN)'
task(:increment) { process_kill(:TTIN) }
desc 'Unicornのワーカープロセスを減らす(TTOU)'
task(:decrement) { process_kill(:TTOU) }
desc 'Unicornプロセスの親子関係を確認(pstree)'
task(:pstree) do
pid_path = ENV['PID_PATH'] || DEFAULT_PID_PATH
unless File.exist?(pid_path)
p "Not found: #{pid_path}"
exit 1
end
sh "pstree `cat #{pid_path}`"
end
# killシグナルを送る
def process_kill(signal)
pid_path = ENV['PID_PATH'] || DEFAULT_PID_PATH
unless File.exist?(pid_path)
p "Not found: #{pid_path}"
exit 1
end
sh "kill -#{signal} `cat #{pid_path}`"
end
end
使い方
タスク一覧出すだけで、コマンドと内容が分かります。
やはり日本語だと分かりやすいですね。
$ rails -T rails unicorn:decrement # Unicornのワーカープロセスを減らす(TTOU) rails unicorn:graceful # Unicorn緩やかな再起動(USR2) rails unicorn:increment # Unicornのワーカープロセスを増やす(TTIN) rails unicorn:pstree # Unicornプロセスの親子関係を確認(pstree) rails unicorn:restart # Unicorn再起動(HUP) rails unicorn:start # Unicorn起動(bundle exec unicorn) rails unicorn:stop # Unicorn停止(QUIT)
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/c7d9cf570ce15d33d31094dae65c91cdb800983d

“Unicornをかなり良い感じに設定” に対して1件のコメントがあります。