Node.js detecta el error ENOMEM lanzado después del spawn

82

Mi script de Node.js se bloquea debido a una excepción errnoException de ENOMEM (memoria insuficiente) al usar spawn .

El error:

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)

Ya estoy usando oyentes para el evento errory exit, pero ninguno de ellos es despedido en caso de este error.

Mi código:

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

Código fuente completo disponible .

¿Hay algo que pueda hacer para evitar que el script se bloquee? ¿Cómo detecto el error ENOMEM lanzado?

¡Gracias!

tobi
fuente
¿Tiene una imagen de ejemplo que se pueda usar para replicar el problema?
mscdex
Ocurre cuando el servidor se queda sin memoria y no se puede reproducir con una imagen en particular. Eso hace que sea difícil de probar: - /
tobi
¿Qué estás haciendo dentro del errorcontrolador?
mscdex
1
¿Encontraste una solución a este problema?
sffc
2
Creo que este es un defecto fundamental al usar fork()(la llamada al sistema subyacente). Ver github.com/nodejs/node/issues/25382
ZachB

Respuestas:

201

Tuve el mismo problema y resultó que mi sistema no tenía espacio de intercambio habilitado . Verifique si este es el caso ejecutando el comando 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

Mirando la fila inferior podemos ver que tenemos un total de memoria de intercambio de 0 bytes. No está bien. El nodo puede consumir bastante memoria y si no hay espacio de intercambio disponible cuando se agota la memoria, es probable que se produzcan errores.

El método para agregar un archivo de intercambio varía entre sistemas operativos y distribuciones, pero si está ejecutando Ubuntu como yo, puede seguir estas instrucciones para agregar un archivo de intercambio :

  1. sudo fallocate -l 4G /swapfile Cree un archivo de intercambio de 4 gigabytes
  2. sudo chmod 600 /swapfile Asegure el archivo de intercambio restringiendo el acceso a la raíz
  3. sudo mkswap /swapfile Marcar el archivo como espacio de intercambio
  4. sudo swapon /swapfile Habilita el intercambio
  5. echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstabPersistir el archivo de intercambio durante los reinicios (¡gracias por el consejo, bman !)
Kaivosukeltaja
fuente
14
Solo una nota para cualquier persona en el futuro que esté leyendo esta respuesta. Swapfile no es persistente al reiniciar. Para que sea persistente, debe editar el archivo / etc / fstab y agregar una línea al final: / swapfile none swap sw 0 0
bman
Solo darle a mi estúpida VM 2 gigas más de RAM resolvió mi problema anterior.
Thomson Comer
2
¿Es esta una buena idea en un servidor de producción? Tengo entendido que cuando el sistema operativo comienza a usar memoria de intercambio, el rendimiento puede degradarse drásticamente, por lo que es mejor dimensionar su servidor con suficiente RAM para manejar las necesidades de las aplicaciones y buscar agresivamente las fugas de memoria.
Josh
2
@josh, cuando la RAM se agota, sucederá una de dos cosas: la memoria se paginará en un archivo de intercambio o cualquier solicitud de memoria adicional fallará con resultados inesperados. Sí, el rendimiento puede degradarse cuando se usa un archivo de intercambio, pero lo tomaré cualquier día sobre la otra opción, especialmente en producción.
Kaivosukeltaja
¿No hice el doble de memoria y necesito cambiar el tamaño? ¿Cómo hago esto?
Jack
4

Si alguna vez se encuentra con este problema en AWS Lambda, debería considerar aumentar la memoria asignada a la función.

James Shapiro
fuente
2

Puede intentar cambiar la cantidad de memoria que utiliza el nodo con este comando: node ----max-old-space-size=1024 yourscript.js

--max-old-space-size = 1024 asignará 1 giga de memoria.

Por defecto, el nodo usará 512 MB de RAM, pero dependiendo de su plataforma, es posible que deba asignar más o menos para que la recolección de basura se active cuando la necesite.

Si su plataforma tiene menos de 500 mb de RAM disponible, intente configurar el uso de memoria más bajo a --max-old-space-size = 256.

Deemoe
fuente
1

Tuve el mismo problema y lo solucioné con 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
fuente
0

Solucioné el problema simplemente desactivando y volviendo a activar mi servidor de nodo.

Carlos G
fuente
-5

¡Tienes que eliminar las salidas del proceso llamado!

Un ejemplo de Python se ve así:

import sys
...
sys.stdout.flush()
Tim Long
fuente
no es una pitón