Consommation excessive de mémoire due à la précompilation des assets

Bonjour à tous,

Nous exécutons nos propres instances de Discourse sur OpenShift depuis plusieurs années. Ces derniers mois (depuis janvier 2026 environ, et en cohérence avec la nouvelle approche décrite dans Introducing pre-compiled JS assets for self-hosters et Introducing a new build system for plugins), nous avons observé le scénario suivant :

Lors de la précompilation des assets au moment du build (bundle exec rake assets:precompile:build), cette opération échoue désormais et consomme plus de 20 Go :

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

# se bloque ici pendant longtemps

En examinant la consommation mémoire, nous constatons :

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

Alors qu’auparavant, le processus était plutôt rapide avec une consommation mémoire modérée.

Nous avons essayé de définir des variables d’environnement telles que CI=1 et NODE_OPTIONS="--max-old-space-size=X", mais rien ne semble aider à limiter cette consommation mémoire.

Quelqu’un rencontre-t-il le même problème et, le cas échéant, comment l’avez-vous résolu ?

Merci beaucoup !

Ismael

Pouvez-vous partager une liste des plugins que vous avez installés ?

Votre mémoire totale est-elle de 4 Go ? Si oui, avez-vous configuré un espace d’échange ?

Pouvez-vous partager les spécifications du serveur ?

Bonjour David,

La liste des plugins supplémentaires est la suivante :

#   - Boutons d'échange (utilisés sur la place de marché)
          - git clone --depth=1 https://github.com/jannolii/discourse-topic-trade-buttons.git
          #   - Recherches enregistrées
          - 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
          #   - Documentation de Discourse
          - git clone --depth=1 https://github.com/discourse/discourse-docs.git
          #   - Sondage MSGraph
          - git clone --depth=1 https://github.com/CERN/msgraph-poll-discourse-plugin.git

Cordialement,

Ismael

Bonjour Heliosurge,

Les nœuds disposent de 8 cœurs CPU et 30 Go de RAM. Dans des conditions normales, un forum consommait 1 cœur CPU et au maximum 2 à 3 Go de RAM (y compris la précompilation).

Aucune mémoire d’échange (swap) n’est configurée. J’avais compris que le swap était utilisé ici en cas de contraintes de mémoire, ce qui ne devrait pas être le cas ici. Cependant, je suis plus inquiet quant à la quantité de mémoire consommée, car cela n’a jamais été un problème auparavant.

Cordialement,

Ismael

Eh bien, votre spécification de serveur ne devrait pas avoir besoin d’espace d’échange. Le membre de l’équipe David est probablement le mieux placé pour vous aider.

L’utilisation de la mémoire diminue-t-elle dès que la tâche assets:build est terminée ?

Bonjour @david,

L’utilisation de la mémoire diminue-t-elle dès que la tâche assets:build est terminée ?

Non. J’ai creusé davantage et il y a quelque chose d’étrange.

Avant le précompilation de build, voici la liste des plugins :

/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

J’ai remarqué le comportement suivant après avoir débogué le code.

/var/www/discourse$ script/rails runner "AssetProcessor.ember_version"
Le nom du plugin est 'msgraph-polling', mais le répertoire du plugin est nommé 'msgraph-poll-discourse-plugin'

# se bloque ici indéfiniment

AssetProcessor.ember_version correspond à la ligne discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub

J’ai donc apporté quelques modifications à ce fichier (ci-joint), essentiellement pour afficher où le processus se bloque lors du traitement, et pour supprimer l’appel à AssetProcessor.ember_version à la ligne discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub, en remplaçant simplement par 5 afin de poursuivre la génération hexadécimale.

Ensuite, j’ai réduit le parallélisme à 1 pour simplifier les choses à la ligne discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub (parallel_count = [Etc.nprocessors, 1].min).

Après cela, j’ai exécuté bundle exec rake assets:precompile:build, ce qui a donné le résultat suivant :

/var/www/discourse$ bundle exec rake assets:precompile:build
Le nom du plugin est 'msgraph-polling', mais le répertoire du plugin est nommé 'msgraph-poll-discourse-plugin'
[assemble_ember_build] Réutilisation de la build Ember principale existante. Tout est terminé.
Le nom du plugin est 'msgraph-polling', mais le répertoire du plugin est nommé 'msgraph-poll-discourse-plugin'
[Plugin::JsManager] Compilation de 49 plugins...
Compilation de automation...
fin du tri des fichiers
fin du tri des fichiers
        hex_digest 103dc9ebebb80a7065cb8dd41fb3356b30f151f7
########### récursif

# se bloque ici indéfiniment, consommant toute la mémoire

Je soupçonne que cela puisse être lié à la valeur de ulimit (que nous avons définie sur unlimited au lieu de quelque chose comme ulimit -n 1048576;), étant donné que vous ouvrez un grand nombre de fichiers et stockez leur contenu en mémoire (via les appels récursifs).

Faites-moi savoir si cela vous dit quelque chose, ou si vous avez d’autres pistes sur ce qui pourrait causer le problème.

Cordialement,

Ismael

js_manager.rb.txt (7,7 KB)

Il est toujours recommandé d’avoir une zone d’échange (swap). Il est très judicieux d’autoriser le noyau à effectuer une sur-engagement (overcommit). Cela peut considérablement réduire vos besoins en mémoire de pointe.

Je réglerais ces deux points, puis je réessaierais. Pour le sur-engagement, consultez

En termes de diagnostic, il pourrait être utile de vérifier dmesg pour des événements OOM, ce que vous pouvez faire après coup, et également d’exécuter vmstat au moment du blocage.

vmstat 5 5

Voici mon conseil général en matière de diagnostic :

Bonjour @Ed_S,

Merci pour votre message.

J’ai effectué un diagnostic et voici ce que j’obtiens :

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
# nous commençons la précompilation...
 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

La consommation de mémoire a explosé :

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

Et blocage lors de la compilation des plugins :

/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

Pouvez-vous modifier ulimit et vérifier si le comportement ci-dessus se reproduit ?

Cordialement,

Ismael

Ah, vous avez rencontré une OOM, parfait. C’est une preuve définitive. ulimit n’a rien à voir avec ce problème.

Ajoutez de l’espace d’échange (swap). Il n’y a aucune raison de ne pas le faire, sauf un manque d’espace disque. Ajoutez 8 Go ou 16 Go, puis réessayez. Votre objectif est d’atteindre un état fonctionnel. Ensuite, si vous le souhaitez, vous pourrez identifier quel processus consomme trop de mémoire.

Configurez le sur-engagement (overcommit). C’est une bonne pratique qui réduit les problèmes de pic de mémoire. Vous n’avez pas besoin de le comprendre ou de le justifier, faites-le simplement. C’est une partie essentielle d’une bonne configuration Linux. Vérifiez d’abord. C’est aussi simple que ça :

# 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

Salut à tous,

Un grand merci pour tous les conseils que vous nous avez donnés, nous les apprécions vraiment. Nous pensons avoir identifié la cause racine des problèmes de mémoire récents.

Auparavant, l’exécution de bundle exec rake assets:precompile:build au moment de la construction (en tant que root) ne nécessitait ni Redis ni de connexion à la base de données. Ce comportement a changé (réf. : Introducing pre-compiled JS assets for self-hosters et Introducing a new build system for plugins).

Pour nous adapter à cela, nous avons déplacé l’étape bundle exec rake assets:precompile:build vers un conteneur d’initialisation au moment de l’exécution (avant d’exécuter db:migrate, etc.). Cela permet de l’exécuter en tant qu’utilisateur discourse, avec l’accès nécessaire aux services Redis et à la base de données.

Cependant, lors de l’exécution, le processus entre dans une boucle dans lib/plugin/js_manager.rb. En examinant ps -fe, nous constatons que pnpm tente à plusieurs reprises de s’ajouter lui-même, ce qui entraîne une saturation de la mémoire :

...
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
...
# et la liste commence à s'allonger et continue indéfiniment, provoquant la saturation de la mémoire

Lors de nos tests, nous avons constaté que l’exécution du conteneur d’initialisation en tant que root, suivie de npm uninstall -g pnpm puis de npm install -g pnpm@10.28.0, résout la boucle et permet à la compilation des plugins de se terminer avec succès :

...
[Plugin::JsManager] Compilation de 49 plugins...
[Plugin::JsManager] Compilation initiale des plugins terminée en 5,82 s

Ainsi, avant de trop complexifier notre infrastructure et probablement de modifier notre conception, je pense que cette question s’adresse davantage à @david : y a-t-il des projets visant à restaurer le comportement précédent pour assets:precompile:build afin qu’il puisse s’exécuter sans Redis ni connexion à une base de données (similaire à ce que vous faites avec le flux DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS: 0) ?

En passant, et par curiosité : pourquoi l’exécution du processus node en tant qu’utilisateur non root déclenche-t-elle cette boucle d’installation récursive de pnpm, alors que l’exécution en tant que root semble l’éviter ?

Cordialement,
Ismael