Consumo eccessivo di memoria dovuto alla precompilazione delle risorse

Ciao a tutti,

Negli ultimi anni abbiamo eseguito le nostre istanze di Discourse su OpenShift e, negli ultimi mesi (da gennaio 2026 circa, in linea con il nuovo approccio illustrato in Introducing pre-compiled JS assets for self-hosters e Introducing a new build system for plugins), abbiamo osservato il seguente scenario:

Quando si precompilano le risorse durante la fase di build (bundle exec rake assets:precompile:build), questa operazione ora fallisce e consuma oltre 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
Installazione riuscita di prometheus_exporter-2.2.0
1 gem installata
Il nome del plugin è 'msgraph-polling', ma la directory del plugin è denominata 'msgraph-poll-discourse-plugin'
[assemble_ember_build] Nessun file di informazioni di build esistente trovato.
Download ed estrazione di https://get.discourse.org/discourse-assets/2026.5.0-latest-03484cbd/production.tar.gz...
  % Totale    % Ricevuto % Xferd  Velocità media   Tempo    Tempo     Tempo     Corrente
                                 Dload  Upload   Totale   Svolto    Mancante   Corrente
  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
Risorse precompilate scaricate ed estratte con successo.
[assemble_ember_build] Riutilizzo della build core di Ember esistente. Tutto fatto.
Il nome del plugin è 'msgraph-polling', ma la directory del plugin è denominata 'msgraph-poll-discourse-plugin'
[Plugin::JsManager] Compilazione di 49 plugin...

# si blocca qui per molto tempo

Osservando il consumo di memoria, vediamo:

Ogni 1,0s: free -h                             webapp-test-discourse-689b5fcb4d-fd2dp-debug-b7nn2: lun mag  4 14:15:57 2026

               totale        usata       libera      condivisa  buff/cache   disponibile
Mem:            28Gi        26Gi       596Mi       524Mi       2,1Gi       1,7Gi
Swap:             0B          0B          0B

mentre in precedenza il processo era piuttosto rapido con un consumo di memoria moderato.

Abbiamo provato a impostare variabili d’ambiente come CI=1 e NODE_OPTIONS="--max-old-space-size=X", ma nulla sembra aiutare a contenere questo consumo di memoria.

Qualcuno sta riscontrando lo stesso problema e, in tal caso, come lo ha risolto?

Grazie mille!

Ismael

Potresti condividere un elenco dei plugin che hai installato?

La tua memoria totale è 4 GB? Se sì, hai configurato uno swap?

Puoi condividere le specifiche del server?

Ciao David,

L’elenco di plugin aggiuntivi è il seguente:

#   - Pulsanti di scambio (utilizzati nel Marketplace)
          - git clone --depth=1 https://github.com/jannolii/discourse-topic-trade-buttons.git
          #   - Ricerche salvate
          - 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
          #   - Documentazione Discourse
          - git clone --depth=1 https://github.com/discourse/discourse-docs.git
          #   - Sondaggio MSGraph
          - git clone --depth=1 https://github.com/CERN/msgraph-poll-discourse-plugin.git

Ciao,

Ismael

Ciao Heliosurge,

I nodi hanno 8 CPU e 30 GiB di RAM. In condizioni normali, un forum consumava 1 CPU e al massimo 2-3 GB di RAM (inclusa la precompilazione).

Non è configurato lo swap. Ho capito che lo swap viene utilizzato qui quando ci sono vincoli di memoria, il che non dovrebbe essere il caso in questo scenario. Tuttavia, sono più “preoccupato” per la quantità di memoria consumata, dato che non è mai stato un problema in precedenza.

Cordiali saluti,

Ismael

Bene, le specifiche del tuo server non dovrebbero richiedere lo swap. Il membro del team David qui è probabilmente la persona più indicata per aiutarti.

L’uso della memoria diminuisce non appena l’attività assets:build è completata?

Ciao @david,

L’utilizzo della memoria diminuisce non appena l’attività assets:build è completata?

No. Ho scavato più a fondo e c’è qualcosa di strano.

Prima di eseguire precompiling:build, ecco l’elenco dei plugin:

/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

Ho notato il seguente comportamento dopo aver eseguito il debug del codice.

/var/www/discourse$ script/rails runner "AssetProcessor.ember_version"
Il nome del plugin è 'msgraph-polling', ma la directory del plugin è denominata 'msgraph-poll-discourse-plugin'

# si blocca qui per sempre

AssetProcessor.ember_version corrisponde alla riga discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub

Quindi ho apportato alcune modifiche a questo file (allegato), principalmente per stampare dove si blocca durante l’elaborazione e per rimuovere AssetProcessor.ember_version in discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub, inserendo semplicemente 5 per continuare la generazione dell’hex.

Poi, ho ridotto il parallelismo a 1 per semplificare le cose in discourse/lib/plugin/js_manager.rb at latest · discourse/discourse · GitHub (parallel_count = [Etc.nprocessors, 1].min).

Dopo ciò, ho eseguito bundle exec rake assets:precompile:build, ottenendo il seguente risultato:

/var/www/discourse$ bundle exec rake assets:precompile:build
Il nome del plugin è 'msgraph-polling', ma la directory del plugin è denominata 'msgraph-poll-discourse-plugin'
[assemble_ember_build] Riutilizzo della build core di Ember esistente. Tutto fatto.
Il nome del plugin è 'msgraph-polling', ma la directory del plugin è denominata 'msgraph-poll-discourse-plugin'
[Plugin::JsManager] Compilazione di 49 plugin...
Compilazione di automation...
fine dei file.sort
fine dei file.sort
        hex_digest 103dc9ebebb80a7065cb8dd41fb3356b30f151f7
########### ricorsivo

# si blocca qui per sempre, consumando tutta la memoria

Sospetto che possa essere correlato al valore ulimit (che abbiamo impostato su unlimited invece di qualcosa come ulimit -n 1048576;), dato che si aprono un numero piuttosto elevato di file e se ne memorizza il contenuto in memoria (tramite le chiamate ricorsive).

Fammi sapere se questo ti suona familiare o se hai altri indizi su quale possa essere il problema.

Ciao,

Ismael

js_manager.rb.txt (7.7 KB)

È sempre consigliabile avere uno swap. È un’ottima idea abilitare il kernel all’overcommit. Ciò può ridurre sostanzialmente il picco delle tue necessità di memoria.

Risolvere prima queste due cose e poi riprovare. Per quanto riguarda l’overcommit, consulta

Per la diagnosi, potrebbe essere utile controllare dmesg per eventi OOM, che puoi fare in seguito, e anche eseguire vmstat al momento del blocco.

vmstat 5 5

Ecco il mio consiglio generale sulla diagnosi:

Ciao @Ed_S,

Grazie per il tuo messaggio.

Ho eseguito la diagnosi e questo è il risultato:

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
# iniziamo la precompilazione...
 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

Il consumo di memoria è schizzato alle stelle:

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

E il processo si blocca durante la compilazione dei plugin:

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

# si blocca qui fino a ottenere un OOMKilled

Sei in grado di modificare ulimit e verificare se si riproduce il comportamento sopra descritto?

Cordiali saluti,

Ismael

Ah, hai visto un OOM, ottimo. È definitivo. ulimit non c’entra nulla con questo.

Aggiungi swap. Non c’è motivo per non farlo, a meno che non manchi spazio su disco. Aggiungi 8G o 16G e riprova. L’obiettivo è raggiungere uno stato funzionante. Successivamente, se lo desideri, puoi provare a misurare quale processo sta causando il problema.

Configura l’overcommit. È una buona pratica e riduce i problemi di picco di memoria. Non hai bisogno di capirlo o giustificarlo, fallo semplicemente. Fa parte di una configurazione Linux corretta. Controlla prima. È così semplice:

# 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

Ciao a tutti,

Grazie mille per tutti i consigli che ci avete fornito, sono molto apprezzati. Crediamo di aver individuato la causa principale dei recenti problemi di memoria.

In precedenza, l’esecuzione di bundle exec rake assets:precompile:build al momento della build (come root) non richiedeva né Redis né una connessione al database. Questo comportamento è cambiato (rif: Introducing pre-compiled JS assets for self-hosters e Introducing a new build system for plugins).

Per adattarci a questa situazione, abbiamo spostato il passaggio bundle exec rake assets:precompile:build in un container init durante l’esecuzione (prima di eseguire db:migrate, ecc.). Questo permette di eseguirlo come utente discourse, con l’accesso necessario ai servizi sia per Redis che per il database.

Tuttavia, durante l’esecuzione, il processo va in un loop in lib/plugin/js_manager.rb. Osservando ps -fe, vediamo che pnpm tenta ripetutamente di aggiungersi, portando alla saturazione della memoria:

...
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
...
# e l'elenco continua a crescere all'infinito, provocando la saturazione della memoria

Nei nostri test, abbiamo scoperto che eseguire il container init come root, seguito da npm uninstall -g pnpm e poi npm install -g pnpm@10.28.0, risolve il loop e permette alla compilazione dei plugin di completarsi con successo:

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

Quindi, prima di sovradimensionare la nostra infrastruttura e probabilmente cambiare il nostro design, penso che questa domanda sia più per @david: ci sono piani per ripristinare il comportamento precedente per assets:precompile:build, in modo che possa essere eseguito senza Redis o una connessione al DB (simile a quanto si fa con il flusso DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS: 0)?

A margine, e per pura curiosità: perché l’esecuzione del processo node come utente non root innesca questo loop ricorsivo di installazione di pnpm, mentre l’esecuzione come root sembra evitarlo?

Un saluto,
Ismael