Ruby 2.6でunicornがrestartしない
あるRailsアプリケーションで使用しているRubyを2.5から2.6に上げたところ、unicornがrestartしてくれなくてハマった。 その時の問題と解決方法をメモ。
エラー内容
restartに失敗しているunicornのerror logを見てみると、次のようなエラーが出力されていた。
/path/to/config/unicorn/production.rb:29:in `block in reload': undefined method `chomp' for nil:NilClass (NoMethodError)
このconfig/unicorn/production.rb
は次のようになっていた。
# snip before_exec do |server| # snip env = ENV.to_hash %w(RUBYLIB RUBYOPT GEM_HOME).each do |key| env.delete(key) end rubylib = IO.popen([env, 'bundle', 'exec', 'env', unsetenv_others: true], &:read).slice(/^RUBYLIB=(.+)$/, 1).chomp ENV['RUBYLIB'] = rubylib end
エラーが起きている29行目は、このコード片の下から3行目、IO.popen
の結果をchomp
しているところである。
このコードは次のブログ記事のものを利用している。
エラーの原因
このエラーはRuby 2.6からBundlerがdefault gemとしてRuby本体に添付されたことに起因する。1
元の記事にもあるとおり、BundlerはRUBYLIB
環境変数を使用して自身のコードを子プロセスのRubyに読ませようとする。
ところがRuby 2.6からはBundlerがdefault gemとして添付されたため、それを使う限りはRUBYLIB
環境変数をセットしなくても子プロセスのRubyからBundlerのコードを読めるようになった。
そのため、BundlerはRUBYLIB
環境変数をセットしないようになった。
先に示したコードではslice(/^RUBYLIB=(.+)$/, 1)
を実行しているが、これはRUBYLIB
環境変数が存在しない時にはnil
を返す。
そのためこのコードでエラーが起きてしまっていた。
解決方法
次のようなパッチを当てた。
- rubylib = IO.popen([env, 'bundle', 'exec', 'env', unsetenv_others: true], &:read).slice(/^RUBYLIB=(.+)$/, 1).chomp - ENV['RUBYLIB'] = rubylib + rubylib = IO.popen([env, 'bundle', 'exec', 'env', unsetenv_others: true], &:read).slice(/^RUBYLIB=(.+)$/, 1)&.chomp + ENV['RUBYLIB'] = rubylib if rubylib
String#chomp
の呼び出しにSafe Navigation Operatorを使用し、またRUBYLIB
環境変数はRUBYLIB
環境変数がセットされている場合にのみ上書きするように変更した。
単にこのコードを削除することでも解決はするが、そうするとgem install bundler
した場合にうまく動かないように思えたので、今回の対応を行った。2