シングルモードとクラスタモードの設定フックを追加

puma/puma

Pumaに、実行モードに応じて条件分岐できる singlecluster 設定フックが追加されました。これにより、フォーク非対応のライブラリを扱うアプリケーションでも、単一の設定ファイル内でモード別の初期化処理を記述できるようになります。

背景

JVMをRuby-Java Bridge(RJB)経由で読み込むアプリケーションでは、JVMのフォーク非対応という制約により初期化タイミングの制御が必要でした。#3571で報告されたように、クラスタモードでは on_worker_boot 内でJVMを読み込む必要がある一方、シングルモードでは別の初期化処理が必要になります。

従来は環境変数でモードを判定するか、設定ファイルを分離する必要がありました。Pumaは lib/puma/dsl.rb 内部で @options[:workers] の値を基にモード判定を行っていましたが、これは公開APIではなく、ユーザーコードから利用できませんでした。単一の config/puma.rb で両モードに対応する設定を記述する手段が求められていました。

技術的な変更

lib/puma/dsl.rbsinglecluster の2つのDSLメソッドが追加されました。これらはブロックを受け取り、実行モードに応じて評価されます。

def single(&block)
  raise ArgumentError, "A block must be provided to `single`" unless block

  @options[:single] ||= []
  @options[:single] << block
end

def cluster(&block)
  raise ArgumentError, "A block must be provided to `cluster`" unless block

  @options[:cluster] ||= []
  @options[:cluster] << block
end

両メソッドはブロックを配列に格納し、後で順次実行する仕組みです。ブロックが渡されない場合は ArgumentError を発生させます。

lib/puma/configuration.rbclamp メソッドに、新しい run_mode_hooks メソッドの呼び出しが追加されました。

def clamp
  load unless @loaded
  run_mode_hooks
  set_conditional_default_options
  @_options.finalize_values
  @clamped = true
end

def run_mode_hooks
  workers_before = @_options[:workers]
  key = workers_before > 0 ? :cluster : :single

  @_options.all_of(key).each(&:call)

  unless @_options[:workers] == workers_before
    raise "cannot change the number of workers inside a #{key} configuration hook"
  end
end

run_mode_hooks は、設定ファイル読み込み後かつオプション確定前のタイミングで実行されます。:workers の値でモードを判定し、対応するフックブロックを順次実行します。フック内で :workers の値が変更された場合はエラーを発生させ、モード判定の整合性を保ちます。

使用例は以下のようになります:

single do
  # シングルモード時のみ実行
  silence_fork_callback_warning
end

cluster do
  # クラスタモード時のみ実行
  prune_bundler
end

設計判断

設定ファイル内での条件分岐をサポートする方式が採用されました。

代替案として、環境変数による外部からの制御や、モード別の設定ファイル分離が考えられました。しかし、本実装では config/puma.rb 内で完結する条件分岐を選択しています。これにより、モード判定ロジックとそれに基づく設定を同一ファイル内で管理できます。

フックの実行タイミングは clamp メソッド内、具体的には set_conditional_default_options の前に配置されました。これは、フック内で設定した値がデフォルト値の条件判定に影響を与えられるようにするためです。例えば、cluster ブロック内で prune_bundler を設定した場合、その値が :preload_app のデフォルト値計算に反映されます。

:workers の値変更を禁止する制約も重要な設計判断です。フック実行前の :workers の値でモードが決定されるため、フック内での変更を許すとモード判定の前提が崩れます。テストでは、この制約違反時に適切なエラーが発生することが検証されています。

本PRは、Pumaの内部で既に使用されていたモード判定ロジックを公開APIとして整備した変更といえます。@options[:workers] > 0 という単純な条件判定を、ユーザーコードから安全に利用できる形でカプセル化しています。JVMのようなフォーク非対応ライブラリの初期化タイミング制御という具体的なユースケースに対し、環境変数や設定ファイル分離に頼らない解決策を提供しました。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)、背景・技術詳細・設計判断(各論)、まとめ(結論)の3部構成が明確です。各セクションが期待される役割を適切に果たしています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```ruby:path/to/file.rb)や、PR/Issue番号のリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

PumaやRuby on Railsに関する専門知識を持つエンジニアを対象としており、専門用語(JVM, RJB, on_worker_boot)の使い方が適切で、過度な初心者向けの説明がありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論パラグラフで始まり、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が遵守されています。これにより高い可読性が確保されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコードブロックは、提供されたDiffの内容(lib/puma/dsl.rb, lib/puma/configuration.rb)を正確に引用しており、ファイルパスも一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Puma関連の用語(`clamp`, `prune_bundler`, `:preload_app`など)や、背景となる技術(JVM, Ruby-Java Bridge)の用語が正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

フックの実行タイミング、`:workers`の値変更が禁止されている理由、デフォルト値への影響など、技術的な説明がDiffの内容と整合しており、正確かつ論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのタイトル、関連Issue(#3571)、Diffの内容によって裏付けられており、ハルシネーション(捏造)は検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#3621)や関連Issue番号(#3571)、ファイル名、メソッド名などの固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「シングルモードとクラスタモードの設定フックを追加」は、PRのタイトル「Add single and cluster configuration hooks」を正確に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容はPRとその関連情報に限定されており、バージョンサポート状況など、PR外の根拠のない知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「追加されました」という過去形の表現が、完了したPRの内容を説明する上で適切であり、時間表現の歪曲はありません。