Si eres desarrollador (tanto de NodeJS como de otros lenguajes) seguro que te han contado las maravillas de la asincronía de NodeJS. La idea de asincronía es que se envía una petición, y mientras que se espera a recibirlo, se siguen haciendo otras operaciones. Y no vamos a decir que esto no sea genial, es más, ahí reside su magia, pero hoy vamos a ver algo de la sincronía en NodeJS con lo que tener un especial cuidado si no queremos crear graves problemas en el servidor.

 

Asincronía en NodeJS vs PHP

NodeJS (y en general JavaScript), no trabaja de la forma clásica como lo hace un script en Python o en PHP, si no que es asíncrono por defecto. En Python y PHP claro que se pueden plantear solicitudes asíncronas, pero por defecto son síncronos. Esta característica especial de NodeJS se debe al Event Loop.

Planteemos el siguiente flujo de ejemplo para nuestras pruebas:

  • Hacemos una petición web para pedir datos de un producto en un sistema eCommerce.
  • Enviamos los datos de usuario y el producto a un servicio, que los guardará y procesará para formar parte de un Bigdata.
  • Posteriormente buscamos en la base de datos el producto, y lo devolvemos al usuario para que lo represente en el Frontend.

Un lenguaje síncrono manda el mensaje a la cola y queda bloqueado a la espera de que le devuelva el resultado. En cambio en NodeJS se envía el mensaje pero no se espera, continúa con la siguiente petición a la base de datos y envía los datos. En el caso en el que el servicio donde enviamos los datos esté caído, podemos obtener un error y deberíamos gestionar dicha anomalía.

1
Mucho cuidado con la asincronía en NodeJS

Reventemos nuestro server NodeJS

Vamos a destruir con un ejemplo, que es lo que mola! Teniendo un servidor NodeJS + Express con dos endpoints, uno /normal que devuelve el mensaje normal y otro /loop que nos bloqueará todo el sistema.


const express = require('express');

const app = express();


const bigNumber = 100000000000000000;

app.listen(3000, function() {
console.log('listening on 3000')
})

app.get('/loop', function (req, res) {
console.log('Infinite loop that will break the server.');
for (i=0; i < bigNumber; i++)
{


}
res.send('Exit.');
})

app.get('/normal', function (req, res) {
console.log('Ordinary page.');
res.send('Normal');
})

Si observas el código verás que no es un bucle infinito pero sí muy grande. Si entramos de primeras en /normal, vemos que entra sin problemas. Podemos refrescar la página todas las veces que queramos, que el servidor va a seguir funcionando bien, sin problemas. Si por otro lado entramos en /loop, el servidor se volverá loco, y no mandará la petición. Pero además, si mientras está ahí esperando vamos a /normal, tampoco funciona, hemos bloqueado todo node.

Multihilo en PHP

Ahora veamos cómo actúa PHP en un Apache. Cada vez que vamos a un endpoint (que es un archivo .php en el servidor Apache) crea un nuevo hilo. Este hilo puede consumir más o menos RAM y CPU, pero no bloquea el sistema, salvo que abramos muchos loops. Por otro lado, Apache corta el hilo cuando emplea más de un determinado tiempo máximo, que por defecto está en 120 segundos.

Igual que con node podemos probar el server de la siguiente manera:

  • localhost:3001/normal.php: para el proceso normal.
  • localhost:3001/loop.php: para intentar reventar el server.

Si pruebas a entrar en /normal.php va a la perfección. Pero si entras en /loop.php, no responderá nada; es más, a los dos minutos debería mandar un error. Pero si le das de nuevo a /normal.php funcionará igualmente, salvo que le des muchas veces a /loop.php en cuyo caso Apache abrirá muchos hilos y consumirá toda tu RAM o CPU.

normal.php


<?php
echo "normal";
?>

loop.php


<?php
const bigNumber = 100000000000000000;
for ($i = 1; $i <= bigNumber; $i++) { 
echo $i; 
}
?>
bucle

Reventando el event loop de NodeJS

Conclusión

NodeJS es una gran plataforma, y para nuestro gusto actualmente uno de los mejores lenguaje para Web. Por su asincronicidad, hace que por norma general sea fácil crear aplicaciones, mantenerlas, es potente, es rápido, vamos... todo maravillas. Pero por lo que hemos explicado, debemos tener especial cuidado con los bucles, no solo for whiletambién foreachfiltersmaps y funciones que las usen. 

Pero cada herramienta ha de ser utilizada de forma adecuada, y la decisión está en el programador sobre si el utilizar NodeJS u otras opciones (como Python) para hacer Jobs.