テンプレート経由でのYJITの有効化が機能しない

こんにちは、

私はセルフホスト型の Discourse インストール(2026.5.0-latest)を運用しています。本日、YJIT を有効にしようと試みました。containers/app.yml"templates/enable-ruby-yjit.yml" を追加し、アプリを再構築しました。

再構築が完了すると、興味深い現象が発生しました。Docker コンテナ内で env | grep RUBY_YJIT_ENABLE を実行すると、RUBY_YJIT_ENABLE=1 が表示されました。ここまでは問題ありません。しかし、続けて sudo -u discourse RAILS_ENV=production bundle exec rails runner 'puts "YJIT enabled: #{RubyVM::YJIT.enabled?}"; puts RUBY_DESCRIPTION' を実行すると、以下の結果が得られました:

YJIT enabled: false

ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [x86_64-linux] 

enable-ruby-yjit.yml テンプレートを追加したにもかかわらず、YJIT は有効になっていませんでした。その後、sudo -u discourse RAILS_ENV=production bundle exec rails runner 'puts "GlobalSetting.yjit_enabled=#{GlobalSetting.yjit_enabled}"' を実行すると、GlobalSetting.yjit_enabled= という出力が得られ、値は nil でした。

いろいろと試行錯誤した結果、最終的に containers/app.yml に以下の設定を追加することで YJIT を有効化できました:

env:
  DISCOURSE_YJIT_ENABLED: true

どこかにバグがあることは間違いありません(GlobalSetting.yjit_enabled が nil を返すべきではありません)。しかし、環境変数を設定することで解決しました。このトピックを検索している誰かの助けになれば幸いです。

それは誤った診断ではありませんか?実際に Web サーバーを稼働している Ruby プロセスではなく、新しく生成された Ruby プロセスの ENV を確認しています。

Pitchfork モールドプロセスの /proc/<pid>/environ を確認すると、そこに YJIT 環境変数が存在していることがわかります。

root@raspberrypi5:/var/discourse# cat /proc/3331660/environ | tr '\0' '\n' | grep -i yjit
RUBY_YJIT_ENABLE=1

環境変数の存在を確認しただけでは、Ruby が現在 YJIT を有効にして実行されているかどうかはわかりません。この特定のケースでは、環境変数が設定されていましたが、起動時に Rails が YJIT の有効化(または無効化)に使用する変数を別の何かが上書きしていました。新しい Rails インスタンスでも GlobalSetting.yjit_enabled= が nil を返す理由を他に説明する方法はありません。また、新しい Rails インスタンスで YJIT が無効になる理由もありません。

containers/app.ymlDISCOURSE_YJIT_ENABLED 環境変数を追加した後、

  1. sudo -u discourse RAILS_ENV=production bundle exec rails runner 'puts "YJIT enabled: #{RubyVM::YJIT.enabled?}"; puts RUBY_DESCRIPTION' を実行すると、YJIT enabled: true が返されます。
  2. サーバーのメモリ使用量がようやくわずかに増加しました。
  3. フォーラムで実際に速度向上が見られました。

私の発見を再現するのは簡単です。テンプレートを追加して確認してみてください。

これは誤りです。Ruby レベルでは、この ENV 変数は公式の切り替え手段の一つです。詳細は Ruby の公式ドキュメントをご覧ください。

これも誤りです。DISCOURSE_YJIT_ENABLEDGlobalSetting.yjit_enabledconfig/application.rb 内の config.yjit にのみ影響を与えます。Rails は、YJIT がまだ有効になっていない場合にのみ、この設定を使って YJIT を有効化します。すでに有効になっている YJIT を無効化するものではありません。したがって、環境変数が設定されていても、DISCOURSE_YJIT_ENABLED は何の役割も果たしません。

私の主張をさらに証明するために、Web プロセスで YJIT が有効かどうかを返すプラグインを作成しました。

https://discourse-on-a-pi5.falco.dev/ruby-info

あなたは Rails レベルの切り替えについて混乱していますが、それは不要です。Ruby レベルの切り替えを使用してください。

へえ!つまり、環境変数を使って YJIT が有効かどうかを確実に検出できるってことですね!それは知りませんでした。Ruby のドキュメントへのリンクをありがとうございます。

ただ、少し不思議に思っていることがあります。env | grep RUBY_YJIT_ENABLEを実行すると RUBY_YJIT_ENABLE=1 が返ってくるのに、同じコンテナ内で新しい Rails インスタンスを起動して #{RubyVM::YJIT.enabled?} を出力すると false になるのはどうしてでしょうか?あなたが言及された通り、この環境変数は Ruby レベルで機能するはずです。だから true が出力されるはずです。

おそらくあなたは非常に忙しく、この件は重要ではないでしょうから、回答する必要はありません。自分のサーバーで自分で解決できるはずです。もしよろしければ、あなたのプラグインをいただけますか?Discourse サーバーが YJIT 有効化された Ruby で実行されていることを確実に確認する方法が欲しいのです。

再現を確認した後、あなたの回答を解決策としてマークします。

事前に感謝します!

申し訳ありません、解決しました。

sudo -u discourse は環境変数をクリアしてしまいます。-E フラグを使用すると通常の環境変数が引き継がれるため、この場合 sudo -E -u discourse RAILS_ENV=production bundle exec rails runner 'puts "YJIT enabled: #{RubyVM::YJIT.enabled?}"; puts RUBY_DESCRIPTION' を実行すると、

YJIT enabled: true
ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +YJIT +PRISM [x86_64-linux]

という結果が返ってきます。

テンプレートのみを追加した状態です。

お時間を無駄にしてしまい申し訳ありません。ご回答を解決策としてマークいたしました。お手数をおかけしてすみません。調査とご回答に時間を割いていただき、ありがとうございます。