アセットの事前コンパイルによる過剰なメモリ消費

こんにちは、皆様。

ここ数年、OpenShift 上で Discourse の独自インスタンスを運用しており、過去数ヶ月(2026 年 1 月頃より、Introducing pre-compiled JS assets for self-hosters および Introducing a new build system for plugins で説明されている新しいアプローチとほぼ整合した時期)に、以下の現象を観察しました。

ビルド時にアセットをプリコンパイルする際(bundle exec rake assets:precompile:build)、この処理が暴走し、20GB 以上のメモリを消費するようになりました。

...
gem install prometheus_exporter -v 2.2.0 -i /var/www/discourse/plugins/discourse-prometheus/gems/3.4.7 --no-document --ignore-dependencies --no-user-install
Successfully installed prometheus_exporter-2.2.0
1 gem installed
Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'
[assemble_ember_build] No existing build info file found.
Fetching and extracting https://get.discourse.org/discourse-assets/2026.5.0-latest-03484cbd/production.tar.gz...
  % Total    % Received % Xferd  Average Speed   Time   Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 20.1M  100 20.1M    0     0  22.5M      0 --:--:-- --:--:-- --:--:-- 22.5M
Prebuilt assets downloaded and extracted successfully.
[assemble_ember_build] Reusing existing core ember build. All done.
Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'
[Plugin::JsManager] Compiling 49 plugins...

# ここから長時間フリーズ

メモリ使用量を確認すると以下の通りです。

Every 1.0s: free -h                             webapp-test-discourse-689b5fcb4d-fd2dp-debug-b7nn2: Mon May  4 14:15:57 2026

               total        used        free      shared  buff/cache   available
Mem:            28Gi        26Gi       596Mi       524Mi       2.1Gi       1.7Gi
Swap:             0B          0B          0B

以前は比較的迅速に完了し、メモリ使用量も控えめでした。

CI=1NODE_OPTIONS="--max-old-space-size=X" などの環境変数を設定してみましたが、メモリ消費を抑制できる効果は見られませんでした。

同様の問題に直面している方はおられますか?もしそうであれば、どのように解決されましたか?

よろしくお願いいたします。

イスマエル

インストールされているプラグインのリストを共有していただけますか?

メモリの合計容量は 4GB ですか?もしそうであれば、スワップ設定は行っていますか?

サーバーの仕様を共有していただけませんか?

こんにちは、David さん、

追加プラグインのリストは以下の通りです:

#   - 取引ボタン(マーケットプレイスで使用)
          - git clone --depth=1 https://github.com/jannolii/discourse-topic-trade-buttons.git
          #   - 保存された検索
          - git clone --depth=1 https://github.com/discourse/discourse-saved-searches.git
          #   - Discourse Akismet
          - git clone --depth=1 https://github.com/discourse/discourse-akismet.git
          #   - Prometheus
          - git clone --depth=1 https://github.com/discourse/discourse-prometheus.git
          #   - Discourse ドキュメント
          - git clone --depth=1 https://github.com/discourse/discourse-docs.git
          #   - MSGraph 投票
          - git clone --depth=1 https://github.com/CERN/msgraph-poll-discourse-plugin.git

では、

イスマエル

こんにちは、Heliosurge さん、

ノードは 8 コア CPU / 30 GiB の RAM です。通常の条件下では、フォーラムは 1 CPU と最大 2〜3 GB の RAM(プリコンパイルを含む)しか消費していませんでした。

スワップは設定されていません。スワップはメモリ制約がある場合に使用されると理解していましたが、ここではそのような状況はないはずです。しかし、以前は問題なかったメモリ消費量に、むしろ「心配」しています。

よろしくお願いいたします、

イスマエル

さて、あなたのサーバー仕様はスワップを必要としないはずです。こちらのチームメンバーであるデビッドが最もよくお手伝いできるでしょう。

アセット:ビルドタスクが完了すると、メモリ使用量はすぐに減少しますか?

@david さん、こんにちは。

アセットのビルドタスクが完了すると、メモリ使用量はすぐに減少しますか?

いいえ。さらに詳しく調査したところ、何か奇妙なことが起きているようです。

precompiling:build 実行前のプラグインリストは以下の通りです。

/var/www/discourse$ ls plugins/
automation           discourse-akismet           discourse-data-explorer  discourse-hcaptcha           discourse-microsoft-auth  discourse-post-voting  discourse-saved-searches       discourse-user-notes           styleguide
chat                 discourse-apple-auth        discourse-details        discourse-lazy-videos        discourse-narrative-bot   discourse-presence     discourse-solved               discourse-zendesk-plugin
checklist            discourse-assign            discourse-docs           discourse-local-dates        discourse-oauth2-basic    discourse-prometheus   discourse-subscriptions        footnote
discourse-adplugin   discourse-cakeday           discourse-gamification   discourse-login-with-amazon  discourse-openid-connect  discourse-reactions    discourse-templates            msgraph-poll-discourse-plugin
discourse-affiliate  discourse-calendar          discourse-github         discourse-lti                discourse-patreon         discourse-rewind       discourse-topic-trade-buttons  poll
discourse-ai         discourse-chat-integration  discourse-graphviz       discourse-math               discourse-policy          discourse-rss-polling  discourse-topic-voting         spoiler-alert

コードのデバッグ中に、以下の動作に気づきました。

/var/www/discourse$ script/rails runner "AssetProcessor.ember_version"
プラグイン名は 'msgraph-polling' ですが、プラグインディレクトリ名は 'msgraph-poll-discourse-plugin' です

# ここから永遠にフリーズ

AssetProcessor.ember_version は、discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub の行に対応しています。

そこで、このファイルにいくつかの変更を加えました(添付参照)。具体的には、処理中にどこで停止するかを出力し、discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHubAssetProcessor.ember_version を削除して、16 進数生成を継続するために 5 を直接設定しました。

その後、discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub で並列度を 1 に減らして処理を容易にしました(parallel_count = [Etc.nprocessors, 1].min)。

この後、bundle exec rake assets:precompile:build を実行した結果は以下の通りです。

/var/www/discourse$ bundle exec rake assets:precompile:build
プラグイン名は 'msgraph-polling' ですが、プラグインディレクトリ名は 'msgraph-poll-discourse-plugin' です
[assemble_ember_build] 既存の Core Ember ビルドを再利用しています。完了しました。
プラグイン名は 'msgraph-polling' ですが、プラグインディレクトリ名は 'msgraph-poll-discourse-plugin' です
[Plugin::JsManager] 49 個のプラグインをコンパイル中...
automation をコンパイル中...
ファイルのソート終了
ファイルのソート終了
        hex_digest 103dc9ebebb80a7065cb8dd41fb3356b30f151f7
########### 再帰処理

# ここから永遠にフリーズし、メモリを全容量消費

これは ulimit の値(現在は unlimited に設定されており、ulimit -n 1048576; のような値ではなく)に関連している可能性が高いと考えています。再帰呼び出しを通じて非常に多くのファイルを開き、その内容をメモリに格納しているためです。

この状況が何か思い当たる節がありますか?あるいは、問題の原因について他のヒントがあれば教えてください。

よろしくお願いいたします。

Ismael

js_manager.rb.txt|添付ファイル (7.7 KB)

スワップ領域を確保しておくことは常に推奨されます。カーネルにオーバーコミットを有効にすることも非常に良いアイデアです。これにより、ピーク時のメモリ需要を大幅に削減できます。

まずこの 2 つの対応を行い、その後にもう一度お試しください。オーバーコミットについては、以下を参照してください。

診断については、後で dmesg を確認して OOM(Out Of Memory)イベントがないかチェックすること、およびストール発生時に vmstat を実行することが役立つ可能性があります。

vmstat 5 5

以下は私の一般的な診断アドバイスです。

こんにちは、@Ed_S さん、

ご連絡ありがとうございます。

診断を行いましたが、以下のような結果が得られました。

vmstat 5 200
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0      0 19595924    104 3919416    0    0  4173    32  439 1040  5  1 93  0  0
 1  0      0 19595924    104 3919416    0    0     0   154 4249 6449  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0     0    39 4399 6778  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0    12    75 5414 8640  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0    51    69 4248 6637  1  1 99  0  0
 1  0      0 19595924    104 3919416    0    0     0    83 4441 6784  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0     9    53 6111 9254  2  1 97  0  0
 1  0      0 19595924    104 3919416    0    0     0   887 4854 7373  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0     0    40 4705 7319  1  1 98  0  0
 1  0      0 19595924    104 3919416    0    0     0    37 4701 7305  1  1 98  0  0
# we start precompiling...
 3  0      0 19595924    104 3919416    0    0   124   902 8292 10254 19  5 75  0  0
 2  0      0 19595924    104 3919416    0    0 43073  6829 13702 16200 11  4 82  4  0
 2  0      0 19595924    104 3919416    0    0 19624   815 12340 15581 10  4 83  3  0
 2  0      0 19595924    104 3919416    0    0  1818  3953 7554 9248 13  3 84  0  0
 2  0      0 19595924    104 3919416    0    0     0    99 7475 8661 16  2 82  0  0
 2  0      0 19595924    104 3919416    0    0     0    52 7634 9084 13  2 84  0  0
 2  0      0 19595924    104 3919416    0    0   115   585 6843 8121 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0 13139 7254 8444 13  2 84  0  0
 2  0      0 19595924    104 3919416    0    0     3  1305 8740 11091 14  2 83  0  0
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 5  0      0 19595924    104 3919416    0    0   465  9798 8403 9279 13  2 85  0  0
 3  0      0 19595924    104 3919416    0    0     6    99 7264 8993 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0    96 7190 8627 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0    66 6869 8299 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0   109 7075 8521 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     3    78 8763 11295 14  2 83  0  0
 2  0      0 19595924    104 3919416    0    0     0  3075 7337 8358 13  2 85  0  0
 4  0      0 19595924    104 3919416    0    0     6   133 7016 8697 13  2 85  0  0
 3  0      0 19595924    104 3919416    0    0     0    45 7005 8370 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0   134 7330 9011 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0    26    86 7239 8747 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0     0   127 8809 11618 15  3 83  0  0
 2  0      0 19595924    104 3919416    0    0     6  1473 7142 8352 13  2 85  0  0
 2  0      0 19595924    104 3919416    0    0  2021   136 8041 10138 13  3 84  0  0
 2  0      0 19595924    104 3919416    0    0  4457   664 6913 7927 12  3 84  0  0

メモリ使用量が急増しました。

               total        used        free      shared  buff/cache   available
Mem:            28Gi        26Gi       460Mi       518Mi       2.3Gi       1.8Gi
Swap:             0B          0B          0B

プラグインのコンパイル中にフリーズしました。

/var/www/discourse$ bundle exec rake assets:precompile:build

gem install prometheus_exporter -v 2.2.0 -i /var/www/discourse/plugins/discourse-prometheus/gems/3.4.7 --no-document --ignore-dependencies --no-user-install
Successfully installed prometheus_exporter-2.2.0
1 gem installed

A new release of RubyGems is available: 3.6.9 → 4.0.11!
Run `gem update --system 4.0.11` to update your installation.

Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'
[assemble_ember_build] No existing build info file found.
Fetching and extracting https://get.discourse.org/discourse-assets/2026.5.0-latest-6b98fe35/production.tar.gz...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--  0     0    0     0    0     0      0      0 --:--:-- --:--  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 20.1M  100 20.1M    0     0  20.8M      0 --:--:-- --:--:-- --:--:-- 20.8M
Prebuilt assets downloaded and extracted successfully.
[assemble_ember_build] Reusing existing core ember build. All done.
Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'
[Plugin::JsManager] Compiling 49 plugins...

# hangs here till giving an OOMKilled

ulimit を変更して、上記の動作が発生するかどうかを確認することは可能でしょうか?

よろしくお願いいたします、

イスマエル

ああ、OOM(メモリ不足)が発生したのですね。素晴らしい、これで確実です。ulimit はこれとは無関係です。

スワップ領域を追加してください。ディスク容量がない場合を除き、追加しない理由はありません。8GB または 16GB 追加して、再度お試しください。まずは動作する状態にすることが重要です。その後、必要に応じてどのプロセスがメモリを圧迫しているかを計測することもできます。

オーバーコミットを設定してください。これは良い習慣であり、ピーク時のメモリ問題を軽減します。理解したり正当化したりする必要はありません。ただ設定するだけです。これは優れた Linux 環境構築の一部です。まずは確認してみましょう。とても簡単です。

# uname -a
Linux ubuntu-4gb-hel1-1 6.8.0-110-generic #110-Ubuntu SMP PREEMPT_DYNAMIC
 Thu Mar 19 17:16:23 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux
# cat /proc/sys/vm/overcommit_memory
1

こんにちは皆さん、

これまで提供していただいた多くのアドバイスに心から感謝しています。最近のメモリ問題の原因を特定できたと考えています。

以前は、ビルド時に(root として)bundle exec rake assets:precompile:buildを実行しても、Redis やデータベースへの接続は不要でした。しかし、この動作は変更されました(参照:Introducing pre-compiled JS assets for self-hosters および https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713)。

これに対応するため、bundle exec rake assets:precompile:buildのステップを、db:migrate などの実行前に init コンテナ内で実行するよう変更しました。これにより、Redis とデータベースの両方への必要なサービスアクセス権を持つ discourse ユーザーとして実行できるようになります。

しかし、実行中にプロセスが lib/plugin/js_manager.rb 内のループに陥っています。ps -feを確認すると、pnpm が繰り返し自身を追加しようとしており、これがメモリ飽和を引き起こしていることがわかります:

...
discour+     704     688  5 11:00 pts/0    00:00:00 node /usr/bin/pnpm -C=frontend/asset-processor node build.js
discour+     718     704  5 11:00 pts/0    00:00:00 node /usr/bin/pnpm add pnpm@10.28.0 --loglevel=error --allow-build=@pnpm
discour+     729     718  6 11:00 pts/0    00:00:00 node /usr/bin/pnpm add pnpm@10.28.0 --loglevel=error --allow-build=@pnpm
discour+     740     729  6 11:00 pts/0    00:00:00 node /usr/bin/pnpm add pnpm@10.28.0 --loglevel=error --allow-build=@pnpm
discour+     754     740  7 11:00 pts/0    00:00:00 node /usr/bin/pnpm add pnpm@10.28.0 --loglevel=error --allow-build=@pnpm
...
# リストは増加し続け、メモリ飽和を引き起こします

テストの結果、init コンテナを root として実行し、npm uninstall -g pnpm の後に npm install -g pnpm@10.28.0 を実行することで、このループが解消され、プラグインのコンパイルが正常に完了することがわかりました:

...
[Plugin::JsManager] Compiling 49 plugins...
[Plugin::JsManager] Finished initial compilation of plugins in 5.82s

したがって、インフラを過剰に設計したり、設計を変更したりする前に、@david にお伺いしたいのですが、assets:precompile:build の以前の動作(Redis や DB 接続なしで実行可能)を復元する予定はありますか?(DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS: 0 フローで実施されていることと同様に)

余談ですが、好奇心から質問させてください:なぜ非 root ユーザーとして node プロセスを実行すると、この再帰的な pnpm インストールループがトリガーされるのに、root として実行すると回避されるのでしょうか?

よろしくお願いいたします、
イスマエル