検索すると沢山でてきて、困らないのですが、
もっと運用しやすいようにログ出したり、エラーハンドリングしたり、作り込んでみました。
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件のコメントがあります。