Node.js przechwytuje błąd ENOMEM zgłoszony po spawn

84

Mój skrypt Node.js ulega awarii z powodu wyrzuconego wyjątku ENOMEM (brak pamięci) errnoException podczas używania spawn .

Błąd:

child_process.js:935
  throw errnoException(process._errno, 'spawn');
        ^

Error: spawn ENOMEM
  at errnoException (child_process.js:988:11)
  at ChildProcess.spawn (child_process.js:935:11)
  at Object.exports.spawn (child_process.js:723:9)
  at module.exports ([...]/node_modules/zbarimg/index.js:19:23)

Używam już detektorów dla zdarzenia errori exit, ale żaden z nich nie jest uruchamiany w przypadku tego błędu.

Mój kod:

zbarimg = process.spawn('zbarimg', [photo, '-q']);
zbarimg.on('error', function(err) { ... });
zbarimg.on('close', function(code) { ... }); 

Dostępny pełny kod źródłowy .

Czy jest coś, co mogę zrobić, aby zapobiec awarii skryptu? Jak wyłapać wyrzucony błąd ENOMEM?

Dzięki!

tobi
źródło
Czy masz przykładowy obraz, który można wykorzystać do odtworzenia problemu?
mscdex
Dzieje się tak, gdy serwerowi brakuje pamięci i nie można go odtworzyć z określonym obrazem. To sprawia, że ​​trudno jest przetestować: - /
tobi
Co robisz w errortreserze?
mscdex
1
Czy znalazłeś rozwiązanie tego problemu?
sffc
2
Myślę, że jest to podstawowa wada przy użyciu fork()(podstawowego wywołania systemowego). Zobacz github.com/nodejs/node/issues/25382
ZachB,

Odpowiedzi:

204

Miałem ten sam problem i jak się okazało, mój system nie miał włączonej przestrzeni wymiany . Sprawdź, czy tak jest, uruchamiając polecenie free -m:

vagrant@vagrant-ubuntu-trusty-64:~$ free -m
             total       used       free     shared    buffers     cached
Mem:          2002        233       1769          0         24         91
-/+ buffers/cache:        116       1885
Swap:            0          0          0

Patrząc na dolny wiersz, widzimy, że mamy w sumie 0 bajtów pamięci wymiany. Niedobrze. Węzeł może bardzo potrzebować pamięci i jeśli nie ma dostępnej przestrzeni wymiany, gdy skończy się pamięć, na pewno wystąpią błędy.

Metoda dodawania pliku wymiany różni się w zależności od systemu operacyjnego i dystrybucji, ale jeśli używasz Ubuntu tak jak ja, możesz postępować zgodnie z tymi instrukcjami dodawania pliku wymiany :

  1. sudo fallocate -l 4G /swapfile Utwórz 4-gigabajtowy plik wymiany
  2. sudo chmod 600 /swapfile Zabezpiecz plik wymiany, ograniczając dostęp do roota
  3. sudo mkswap /swapfile Oznacz plik jako przestrzeń wymiany
  4. sudo swapon /swapfile Włącz zamianę
  5. echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstabUtrzymuj plik wymiany przy ponownym uruchomieniu (dzięki za wskazówkę, bman !)
Kaivosukeltaja
źródło
15
Tylko uwaga dla każdego, kto w przyszłości będzie czytał tę odpowiedź. Swapfile nie jest trwały przy ponownym uruchomieniu. Aby uczynić go trwałym, musisz edytować plik / etc / fstab i dodać linię na końcu: / swapfile none swap swap 0 0
bman
Dając mojemu głupiemu VM 2 więcej pamięci RAM, rozwiązałem powyższy problem.
Thomson Comer
2
Czy to dobry pomysł na serwerze produkcyjnym? Rozumiem, że gdy system operacyjny zaczyna korzystać z pamięci wymiany, wydajność może gwałtownie spaść, dlatego lepiej jest dopasować serwer do wystarczającej ilości pamięci RAM, aby obsłużyć potrzeby aplikacji, i agresywnie wyszukiwać wycieki pamięci.
josh
2
@josh, gdy skończy się pamięć RAM, nastąpi jedna z dwóch rzeczy - albo pamięć zostanie stronicowana do pliku wymiany, albo jakiekolwiek żądania dodatkowej pamięci zakończą się niepowodzeniem z nieoczekiwanymi wynikami. Tak, wydajność może się pogorszyć, gdy używany jest plik wymiany, ale każdego dnia przejmę to od innej opcji, zwłaszcza w środowisku produkcyjnym.
Kaivosukeltaja
Nie podwoiłem pamięci i nie potrzebowałem zmienić rozmiaru? Jak mam to zrobic?
Jack,
5

Jeśli kiedykolwiek napotkasz ten problem w AWS Lambda, powinieneś rozważyć zwiększenie pamięci przydzielonej funkcji.

James Shapiro
źródło
2

Możesz spróbować zmienić ilość używanej pamięci przez węzeł za pomocą tego polecenia: node ----max-old-space-size=1024 yourscript.js

--max-old-space-size = 1024 przydzieli 1 gig pamięci.

Domyślnie węzeł będzie używał 512 MB pamięci RAM, ale w zależności od platformy może być konieczne przydzielenie większej lub mniejszej ilości pamięci, aby zbieranie śmieci działało, gdy tego potrzebujesz.

Jeśli Twoja platforma ma mniej niż 500 MB pamięci RAM, spróbuj ustawić użycie pamięci poniżej --max-old-space-size = 256.

Deemoe
źródło
1

Miałem ten sam problem i naprawiłem go za pomocą try / catch:

try {
  zbarimg = process.spawn('zbarimg', [photo, '-q']);
} catch (err) {
  console.log(err);
}
zbarimg.on('error', function(err) { ... });
zbarimg.on('close', function(code) { ... }); 
Nodarius
źródło
0

Naprawiłem problem, wyłączając i ponownie włączając mój serwer Node.

Carlos G.
źródło
-6

Musisz opróżnić wyjścia z wywołanego procesu!

Przykład w Pythonie wygląda następująco:

import sys
...
sys.stdout.flush()
Tim Long
źródło
to nie jest python