Shimpei Wakida's Blog

日々の学びをゆるりと.

「rails server」コマンド実行時、Pumaはどこの設定を読み込んでいる?

Ruby on Rails Advent Calendar 2022』24日目の記事です。

はじめに

スタートアップでエンジニアリングマネージャーやったりスクラムマスターやったりしている人です。

今回は、「rails serverコマンド打った時、Pumaはどこの設定を読み込んでいるのか?」について調べたので、備忘録として記事にしました。

rails serverコマンド自体の仕組みを解説している記事はそこそこヒットするんですが、意外とrails serverした時のPumaの設定ってどこに書いてあるの?という記事はなかった気がするので、書いてみることにしました。

対象読者は、Rails初学者 〜 経験1・2年くらいの、「Rails開発に少し慣れてきて、動くコードはそれなりに書けるようになってきた気がするけど、内部の仕組みについても少しずつ理解を深めていきたいよ〜」くらいの方がターゲットとなっています。

(時間がない方のために)結論

時間がない忙しいあなたのために、まず結論をお伝えします。

Pumaのソースコード(puma/lib/puma/configration.rb)のpuma_default_optionsというメソッドにデフォルト設定が書いてあり、Railsアプリにconfig/puma.rbconfig/puma/<environment_name>.rbがあるとそれが読み込まれ、デフォルト設定をオーバーライドします。

調べることになったきっかけ

会社のプロダクトはCapistranoでデプロイ行っています。capistrano-pumagemのバージョンを上げるついでに、Pumaの設定ファイルを Capistranoデフォルトであるサーバー上の{app_root}/shared/puma.rbから、Railsアプリの config/puma/<environment_name>.rbを読み込むように変更しました。

この変更の過程で、開発環境でrails serverコマンドを叩いた時に、config/puma.rbファイルがないのにPumaが起動できてしまいました(Railsのデフォルトで config/puma.rbは存在しますが、ファイルリネームされてその時は存在しなかった)。

Puma起動時に 、config/puma.rbconfig/puma/<environment_name>.rb を見に行くことはCapistranoの設定変更で知っていましたが、どちらも存在しないのに起動できたのが不思議でした。

というわけで、「おそらく設定ファイルがなくてもどっかにデフォルトの設定があって、初期値として設定されているんだろう」の仮説のもと、それがどこに書かれているのかを探しにいくことにしました。

Pumaのソースコードに書いてあった

結論、Pumaのソースコードに書いてあったのですが、どうやって見つけたかの過程を残しておきます(他にいい方法あれば教えていただきたい)。

rails newしたときに作られるconfig/puma.rb に書いてある設定のうち、とりあえずworker_timeoutあたりでRubyMineを使って全検索してみる。

Scopeを「All Place」にすると、プロジェクトのソースコードだけでなく、インストールしたGemのソースコードまで検索対象に含めてくれます。

あった!!!

該当のソースコードはこちら

github.com

# puma/lib/puma/configration.rb

def puma_default_options
      {
        :min_threads => 0,
        :max_threads => 16,
        :log_requests => false,
        :debug => false,
        :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
        :workers => 0,
        :daemon => false,
        :mode => :http,
        :worker_timeout => DefaultWorkerTimeout,
        :worker_boot_timeout => DefaultWorkerTimeout,
        :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
        :remote_address => :socket,
        :tag => method(:infer_tag),
        :environment => -> { ENV['RACK_ENV'] || "development" },
        :rackup => DefaultRackup,
        :logger => STDOUT,
        :persistent_timeout => Const::PERSISTENT_TIMEOUT,
        :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
        :raise_exception_on_sigterm => true
      }
    end

puma_default_optionsというメソッド内で、他にもいろいろ定義されているっぽい!

PumaのREADME

さらに、PumaのREADMEを見ると、Configuration Fileのブロックで以下のように書いてありました。

If no configuration file is specified, Puma will look for a configuration file at config/puma.rb. If an environment is specified (via the --environment flag or through the APP_ENV, RACK_ENV, or RAILS_ENV environment variables) Puma looks for a configuration file at config/puma/<environment_name>.rb and then falls back to config/puma.rb.

(訳) 設定ファイルが指定されていない場合、Puma は config/puma.rb にある設定ファイルを探します。環境が指定された場合 (--environment フラグまたは APP_ENV、RACK_ENV、RAILS_ENV 環境変数を使用) Puma は config/puma/<environment_name>.rb から設定ファイルを探し、その後 config/puma.rb にフォールバックします。

要するに、puma_default_optionsで定義されたデフォルト設定があり、config/puma.rbconfig/puma/<environment_name>.rbがあった場合、読み込んでデフォルト設定をオーバーライドしてくれるんですね〜〜

だから、設定ファイルがなくてもデフォルト設定で動かすことができたんですね!(解決!)

おわりに

Railsにある程度の年数触れてきた方にとっては特に目新しさのない内容だったかとは思います。

しかし、個人的にはCapistranoの設定変更に始まり本記事の内容に至るまで、

など、多くのGemのソースコードを読みにいき、とても勉強になりました(と同時に、Capistrano辛いから早くやめたいという気持ちもさらに強くなりましたw)。

「なんか動いた!OK!」のフェーズから、「なぜうまくいったのだろう?」とソースコードを読みに行くフェーズを経ることで、学びは5倍10倍になるんだなあということを改めて実感しました。

参考記事