Rubyと筋肉とギターとわたし

エンジニア二年目の雑魚です。プログラミング・ギター・筋トレのことをメインにブログを書いていきます。

【Rails】unicorn.rbでRails.rootが使えない

どうもてぃです。

本番環境を作ってます。環境ってすごく大事ですよね。

今回何も考えずデフォルトのサーバーpumaを使っていたので、unicornに移行しようと設定していたところ起きた問題です。

環境

起きたこと

worker_processes Integer(ENV['WEB_CONCURRENCY'] || 3)
timeout 15
preload_app true

listen Rails.root.join('tmp', 'unicorn.sock')
pid    Rails.root.join('tmp', 'unicorn.pid')

before_fork do |server, worker|
  Signal.trap 'TEAM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill('QUIT', Process.pid)
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothind. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

stderr_path File.expand_path('log/unicorn.log', Rails.root)
stdout_path File.expand_path('log/unicorn.log', Rails.root)

上記がunicornの設定ファイルです。

これを元にサーバー起動をしてみたところ、以下のエラーが発生。

# lib/tasks/unicorn.rake を実行する
$ bundle exec rails unicorn:start

unicorn -c /home/user/project/config/unicorn.rb -E development -D
Traceback (most recent call last):
    9: from /home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `<main>'
    8: from /home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `load'
    7: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>'
    6: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `new'
    5: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `initialize'
    4: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `new'
    3: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:77:in `initialize'
    2: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:84:in `reload'
    1: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:84:in `instance_eval'
/home/user/project/config/unicorn.rb:5:in `reload': uninitialized constant #<Class:#<Unicorn::Configurator:0x000055a569137798>>::Rails (NameError)
master failed to start, check stderr log for details
rails aborted!
Command failed with status (1): [unicorn -c /home/user/projec...]
/home/user/project/lib/tasks/unicorn.rake:5:in `block (2 levels) in <main>'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/command.rb:48:in `invoke'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => unicorn:start
(See full trace by running task with --trace)

たいていどこのファイルでも問題なくRailsを使えるので何も疑ってなかったのですが、色々調べたところ使えないようです。

やったこと

require 'rails'をやってみたんですが、Rails.rootnilで返ってくる。

故に、joinメソッドでNoMethodErrorが起きるという事態。

そのため、大人しく絶対パスを使って書き直すことにした。

worker_processes Integer(ENV['WEB_CONCURRENCY'] || 3)
timeout 15
preload_app true

# listen Rails.root.join('tmp', 'unicorn.sock')
# pid    Rails.root.join('tmp', 'unicorn.pid')
listen '/home/user/project/tmp/unicorn.sock'
pid '/home/user/project/tmp/unicorn.pid'

before_fork do |server, worker|
  Signal.trap 'TEAM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill('QUIT', Process.pid)
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothind. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

stderr_path File.expand_path('log/unicorn.log', '/home/user/project/')
stdout_path File.expand_path('log/unicorn.log', '/home/user/project/')

これで解決。

おわりに

環境変数を設定すればいいのかもなーと思いました。

本番環境ではそれで行こうかな。