Übermäßiger Speicherverbrauch durch Vorkompilieren von Assets

Hallo zusammen,

wir betreiben seit einigen Jahren eigene Discourse-Instanzen in OpenShift. In den letzten Monaten (ab Januar 2026, grob zeitgleich mit dem neuen Ansatz, der unter Introducing pre-compiled JS assets for self-hosters und Introducing a new build system for plugins vorgestellt wurde), haben wir folgendes Szenario beobachtet:

Beim Vorkompilieren von Assets während des Build-Prozesses (bundle exec rake assets:precompile:build) stürzt dieser Vorgang nun ab und verbraucht mehr als 20 GB:

...
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...

# stucks here for long

Beim Blick auf den Speicherverbrauch sehen wir:

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

Früher verlief dieser Vorgang dagegen recht schnell und mit moderatem Speicherverbrauch.

Wir haben versucht, Umgebungsvariablen wie CI=1 und NODE_OPTIONS="--max-old-space-size=X" zu setzen, doch nichts scheint zu helfen, den Speicherverbrauch in Grenzen zu halten.

Stößt jemand anderes auf dasselbe Problem? Wenn ja, wie habt ihr es gelöst?

Vielen Dank!

Ismael

Können Sie eine Liste der installierten Plugins teilen?

Ist dein Gesamtspeicher 4 GB? Falls ja, hast du eine Swap-Konfiguration eingerichtet?

Kannst du die Server-Spezifikationen teilen?

Hallo David,

Die Liste der zusätzlichen Plugins lautet:

#   - Trade-Buttons (werden auf dem Marktplatz verwendet)
          - git clone --depth=1 https://github.com/jannolii/discourse-topic-trade-buttons.git
          #   - Gespeicherte Suchen
          - 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 Docs
          - git clone --depth=1 https://github.com/discourse/discourse-docs.git
          #   - MSGraph-Umfrage
          - git clone --depth=1 https://github.com/CERN/msgraph-poll-discourse-plugin.git

Viele Grüße,

Ismael

Hallo Heliosurge,

Die Nodes verfügen über 8 CPUs und 30 GiB RAM. Unter normalen Bedingungen verbrauchte ein Forum maximal 1 CPU und 2–3 GB RAM (einschließlich der Vorabkompilierung).

Es ist kein Swap konfiguriert. Ich habe verstanden, dass Swap hier nur bei Speicherengpässen verwendet wird, was hier eigentlich nicht der Fall sein sollte. Allerdings mache ich mir eher Sorgen um den hohen Speicherverbrauch, da dies bisher nie ein Problem war.

Viele Grüße,

Ismael

Nun, deine Server-Spezifikation sollte kein Swap benötigen. Das Team-Mitglied David hier kann wahrscheinlich am besten helfen.

Sinkt die Speichernutzung sofort, nachdem die Aufgabe assets:build abgeschlossen ist?

Hallo @david,

Nimmt der Speicherverbrauch sofort ab, sobald die Aufgabe assets:build abgeschlossen ist?

Nein. Ich habe weiter recherchiert und es gibt etwas Seltsames.

Vor dem Ausführen von precompiling:build sieht die Liste der Plugins so aus:

/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

Beim Debuggen des Codes habe ich folgendes Verhalten festgestellt:

/var/www/discourse$ script/rails runner "AssetProcessor.ember_version"
Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'

# hangs here forever

Die Zeile AssetProcessor.ember_version entspricht discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub.

Daher habe ich einige Änderungen an dieser Datei vorgenommen (siehe Anhang), hauptsächlich um auszugeben, wo der Prozess beim Verarbeiten hängen bleibt, und um AssetProcessor.ember_version in discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub zu entfernen, indem ich einfach 5 einsetze, um die Hex-Generierung fortzusetzen.

Anschließend habe ich die Parallelität auf 1 reduziert, um die Dinge zu vereinfachen, in discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub (parallel_count = [Etc.nprocessors, 1].min).

Danach habe ich bundle exec rake assets:precompile:build ausgeführt, was folgendes Ergebnis lieferte:

/var/www/discourse$ bundle exec rake assets:precompile:build
Plugin name is 'msgraph-polling', but plugin directory is named 'msgraph-poll-discourse-plugin'
[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...
Compiling automation...
end of files.sort
end of files.sort
        hex_digest 103dc9ebebb80a7065cb8dd41fb3356b30f151f7
########### recursive

# hang here forever, consuming the full memory

Ich vermute, dass dies mit dem Wert von ulimit zusammenhängen könnte (der bei uns auf unlimited statt auf etwas wie ulimit -n 1048576; gesetzt ist), da eine sehr große Anzahl von Dateien geöffnet und deren Inhalt im Speicher gespeichert wird (durch rekursive Aufrufe).

Lass mich wissen, ob dir das etwas sagt oder ob du weitere Hinweise hast, woran das Problem liegen könnte.

Viele Grüße,

Ismael

js_manager.rb.txt (7,7 KB)

Es ist immer ratsam, eine Swap-Partition zu haben. Es ist eine sehr gute Idee, dem Kernel die Überbelegung (Overcommit) zu erlauben. Dies kann Ihren Spitzenbedarf an Arbeitsspeicher erheblich reduzieren.

Klären Sie diese beiden Punkte und versuchen Sie es dann erneut. Für Overcommit siehe

Zur Diagnose könnte es hilfreich sein, dmesg auf OOM-Ereignisse zu überprüfen, was Sie im Nachhinein tun können, und außerdem vmstat zum Zeitpunkt des Stillstands auszuführen.

vmstat 5 5

Hier ist mein allgemeiner Diagnose-Rat:

Hallo @Ed_S,

vielen Dank für deine Nachricht.

Ich habe eine Diagnose durchgeführt und hier sind die Ergebnisse:

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
# wir starten das Vorkompilieren...
 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

Der Speicherverbrauch ist stark angestiegen:

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

Und es bleibt beim Kompilieren von Plugins hängen:

/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

Kannst du ulimit anpassen und prüfen, ob sich das oben beschriebene Verhalten erneut zeigt?

Viele Grüße,

Ismael

Ah, Sie haben einen OOM-Fehler gesehen, großartig. Das ist eindeutig. ulimit hat damit nichts zu tun.

Fügen Sie Swap-Speicher hinzu. Es gibt keinen Grund, dies nicht zu tun, außer mangelndem Festplattenspeicher. Fügen Sie 8 GB oder 16 GB hinzu und versuchen Sie es erneut. Ihr Ziel ist es, einen funktionierenden Zustand zu erreichen. Anschließend können Sie, falls gewünscht, messen, welcher Prozess die Probleme verursacht.

Richten Sie Overcommit ein. Das ist gute Praxis und reduziert Probleme mit Spitzenlasten im Arbeitsspeicher. Sie müssen es nicht verstehen oder begründen, führen Sie es einfach durch. Es ist Teil einer guten Linux-Konfiguration. Prüfen Sie es zunächst. So einfach geht’s:

# 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

Hallo zusammen,

vielen Dank für alle Tipps, die ihr uns gegeben habt – das wird sehr geschätzt. Wir glauben, die Grundursache der jüngsten Speicherprobleme identifiziert zu haben.

Früher erforderte die Ausführung von bundle exec rake assets:precompile:build zur Build-Zeit (als root) weder Redis noch eine Datenbankverbindung. Dieses Verhalten hat sich geändert (siehe: Introducing pre-compiled JS assets for self-hosters und Introducing a new build system for plugins).

Um dem Rechnung zu tragen, haben wir den Schritt bundle exec rake assets:precompile:build in einen Init-Container zur Laufzeit verschoben (vor der Ausführung von db:migrate usw.). Dadurch kann er als Discourse-Benutzer mit dem notwendigen Servicezugriff auf Redis und die Datenbank ausgeführt werden.

Allerdings stößt der Prozess während der Ausführung in lib/plugin/js_manager.rb in eine Schleife. Wenn wir ps -fe betrachten, sehen wir, dass pnpm wiederholt versucht, sich selbst hinzuzufügen, was zu einer Speichersättigung führt:

...
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
...
# und die Liste wächst weiter und weiter, was die Speichersättigung verursacht

In unseren Tests haben wir festgestellt, dass die Ausführung des Init-Containers stattdessen als root, gefolgt von npm uninstall -g pnpm und dann npm install -g pnpm@10.28.0, die Schleife auflöst und den erfolgreichen Abschluss der Plugin-Kompilierung ermöglicht:

...
[Plugin::JsManager] Kompilierung von 49 Plugins...
[Plugin::JsManager] Initiale Kompilierung der Plugins in 5,82 s abgeschlossen

Bevor wir unsere Infrastruktur übermäßig komplex machen und wahrscheinlich unser Design ändern, denke ich, dass diese Frage eher an @david gerichtet ist: Gibt es Pläne, das vorherige Verhalten für assets:precompile:build wiederherzustellen, sodass es ohne Redis- oder Datenbankverbindung ausgeführt werden kann (ähnlich wie bei dem DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS: 0-Flow)?

Nebenbei und aus Neugier: Warum löst die Ausführung des node-Prozesses als Nicht-Root-Benutzer diese rekursive pnpm-Installations-Schleife aus, während die Ausführung als root dies zu vermeiden scheint?

Viele Grüße,
Ismael