Rails6 + Springな開発環境で環境変数をたくさん設定したらrails consoleがハングしたw

以下の環境でrails consoleを使おうと思ったらハングしました。

  • Mac OS X 10.14.6
  • Ruby 2.7
  • Rails.envは development
  • Rails 6.0.3.1 or 6.0.3.2
    • Rails 5以下のバージョンではこの現象は起こらないのは確認済
    • Rails 6.0.0 ~ 6.0.3で再現するかは試してない
  • Spring 2.0.1(Springのバージョンは関係ない気がするが念の為)

原因はSpringの内部処理でsocketに環境変数を書き込む下記の処理の際に

# https://github.com/rails/spring/blob/v2.0.1/lib/spring/client/run.rb#L144
def run_command(client, application)
  log "sending command"

  application.send_io STDOUT
  application.send_io STDERR
  application.send_io STDIN

  send_json application, "args" => args, "env" => ENV.to_hash

  ...
ensure
  application.close
end

# https://github.com/rails/spring/blob/v2.0.1/lib/spring/client/run.rb#L206
def send_json(socket, data)
  data = JSON.dump(data)

  socket.puts  data.bytesize
  # 環境変数を書き込む処理
  # dataには `JSON.dump(ENV.to_hash)` が入っている
  socket.write data
end

書き込む環境変数のバイト数が大体128.4KBを超えると書き込みバッファが溢れてるっぽく、ここでハングしてしまってました。環境変数の容量を128.3KB以下に減らしたところハングせずに書き込めたため環境変数の容量が悪いと判断し、使っていなかった変数を消す作業を行い事なきを得ました。

溢れてるっぽく と書いたのは socket.write data 以降の処理にbinding.pryのstepで入れなかったためです。socket.writeの実態はIO#writeで、このメソッドはCで実装されているためこれ以上pryでデバッグできないんじゃないかと思ったのが諦めた背景です(ruby/rubyのコードもデバッグできるようになりたい...)。

後々社内の別の開発者がVM上のubuntu環境で同じ環境変数を用意してrails consoleを実行したところErrno::E2BIGが出ていました。E2BIGはLinuxによって定義されたシステムエラーの1つで、単一の引数や環境変数の文字列が128KBより大きい場合に返されるエラーなので、やはり環境変数の容量の問題だったねーということになりました。