Cola de mensajes en Node.js con AWS SQS

    Introducci贸n

    Con el aumento de la complejidad de los sistemas de software modernos, surgi贸 la necesidad de dividir los sistemas que hab铆an superado su tama帽o inicial. Este aumento en la complejidad de los sistemas hizo que fuera m谩s dif铆cil mantenerlos, actualizarlos y mejorarlos.

    Esto allan贸 el camino para los microservicios que permitieron que los sistemas monol铆ticos masivos se dividieran en servicios m谩s peque帽os que est谩n d茅bilmente acoplados pero que interact煤an para brindar la funcionalidad total de la soluci贸n monol铆tica inicial. El acoplamiento suelto proporciona agilidad y facilita el proceso de mantenimiento y la adici贸n de nuevas funciones sin tener que modificar sistemas completos.

    Es en estas arquitecturas de microservicios donde los sistemas de colas resultan 煤tiles para facilitar la comunicaci贸n entre los servicios separados que componen la configuraci贸n completa.

    En esta publicaci贸n, nos sumergiremos en los sistemas de colas, en particular el Simple Queue Service de Amazon, y demostraremos c贸mo podemos aprovechar sus caracter铆sticas en un entorno de microservicio.

    驴Qu茅 es Message Queue Server?

    Antes de que Internet y el correo electr贸nico entraran en escena, las personas que viv铆an a largas distancias se comunicaban principalmente a trav茅s del intercambio de cartas. Las cartas conten铆an los mensajes que se compartir铆an y se publicaron en la estaci贸n de correos local desde donde ser铆an transferidas a la direcci贸n del destinatario.

    Esto podr铆a haber diferido de una regi贸n a otra, pero la idea era la misma. La gente confiaba en intermediarios para que les transmitieran sus mensajes a medida que avanzaban con sus vidas.

    Cuando un sistema se divide en componentes o servicios m谩s peque帽os que se espera que funcionen juntos, necesitar谩n comunicarse y pasar informaci贸n de un servicio a otro, seg煤n la funcionalidad de los servicios individuales.

    La cola de mensajes facilita este proceso al actuar como el “servicio de oficina postal” para los microservicios. Los mensajes se colocan en una cola y los servicios de destino recogen y act煤an sobre los que se dirigen a ellos. Los mensajes pueden contener cualquier cosa, como instrucciones sobre los pasos a seguir, los datos sobre los que actuar o guardar, o trabajos asincr贸nicos a realizar.

    La cola de mensajes es un mecanismo que permite que los componentes de un sistema se comuniquen e intercambien informaci贸n de manera asincr贸nica. Esto significa que los sistemas d茅bilmente acoplados no tienen que esperar comentarios inmediatos sobre los mensajes que env铆an y pueden liberarse para continuar manejando otras solicitudes. Cuando llega el momento y se requiere la respuesta, el servicio puede buscar la respuesta en la cola de mensajes.

    A continuaci贸n, se muestran algunos ejemplos de colas de mensajes o intermediarios populares:

    Casos de uso de Message Queue Server

    Las colas de mensajes no son necesarias para todos los sistemas, pero existen ciertos escenarios en los que vale la pena el esfuerzo y los recursos necesarios para configurarlas y mantenerlas. Cuando se utilizan apropiadamente, las colas de mensajes son ventajosas de varias formas.

    Primero, las colas de mensajes apoyan el desacoplamiento de grandes sistemas al proporcionar el mecanismo de comunicaci贸n en un sistema d茅bilmente acoplado.

    La redundancia se refuerza mediante el uso de colas de mensajes al mantener el estado en caso de que falle un servicio. Cuando un servicio fallido o defectuoso reanuda las operaciones, todas las operaciones que deb铆a manejar seguir谩n en la cola y puede recogerlas y continuar con las transacciones, que de otro modo podr铆an haberse perdido.

    La cola de mensajes facilita el procesamiento por lotes de operaciones, como enviar correos electr贸nicos o insertar registros en una base de datos. Las instrucciones por lotes pueden guardarse en una cola y procesarse todas al mismo tiempo en orden en lugar de procesarse una por una, lo que puede ser ineficaz.

    Los sistemas de colas tambi茅n pueden ser 煤tiles para garantizar la coherencia de las operaciones al garantizar que se ejecuten en el orden en que se recibieron. Esto es especialmente importante cuando se han replicado componentes o servicios particulares de un sistema para manejar una carga mayor. De esta manera, el sistema escalar谩 bien para manejar la carga y tambi茅n garantizar谩 que las transacciones procesadas sean consistentes y est茅n en orden, ya que todos los servicios replicados obtendr谩n sus instrucciones de la cola de mensajes que actuar谩 como la 煤nica fuente de verdad.

    Servicio de cola simple de Amazon – SQS

    Como la mayor铆a de las otras ofertas de Amazon Web Services, Simple Queue Service (SQS) es una soluci贸n de cola de mensajes distribuida y completamente administrada por Amazon, al igual que la computaci贸n sin servidor a trav茅s de Chalice .

    SQS nos permite enviar y recibir mensajes o instrucciones entre componentes de software, lo que nos permite implementar y escalar microservicios en nuestros sistemas sin la molestia de configurar y mantener un sistema de cola.

    Al igual que otros servicios de AWS, SQS se escala din谩micamente en funci贸n de la demanda y, al mismo tiempo, garantiza la seguridad de los datos transmitidos a trav茅s del cifrado (opcional) de los mensajes.

    Proyecto de demostraci贸n

    Para explorar Amazon Simple Queue Service, crearemos un sistema desacoplado en Node.js, en el que cada componente interactuar谩 con los dem谩s enviando y recuperando mensajes de SQS.

    Dado que somos una organizaci贸n peque帽a que no tiene el ancho de banda para manejar los pedidos a medida que llegan, tendremos un servicio para recibir los pedidos de los usuarios y otro que entregar谩 todos los pedidos publicados ese d铆a en nuestra bandeja de entrada de correo electr贸nico a una hora determinada del d铆a para el procesamiento por lotes. Todos los pedidos se almacenar谩n en la cola hasta que sean recogidos por nuestro segundo servicio y enviados a nuestra bandeja de entrada de correo electr贸nico.

    Nuestros microservicios consistir谩n en API simples de Node.js, una que recibe la informaci贸n del pedido de los usuarios y otra que env铆a correos electr贸nicos de confirmaci贸n a los usuarios.

    Enviar confirmaciones de correo electr贸nico de forma asincr贸nica a trav茅s de la cola de mensajer铆a permitir谩 que nuestro servicio de pedidos contin煤e recibiendo pedidos a pesar de la carga ya que no tiene que preocuparse por enviar los correos electr贸nicos.

    Adem谩s, en caso de que el servicio de correo se caiga, una vez que se vuelva a activar, continuar谩 enviando correos electr贸nicos desde la cola, por lo que no tendremos que preocuparnos por los pedidos perdidos.

    Servicios web de Amazon

    Para este proyecto, necesitaremos una cuenta de AWS activa y v谩lida en la que podamos registrarnos en la p谩gina de inicio de AWS . AWS requiere que no solo ofrezcamos algunos datos personales, sino tambi茅n nuestros datos de facturaci贸n. Para evitar que se le cobre por este proyecto de demostraci贸n, utilizaremos la capa gratuita de AWS con fines de prueba y desarrollo.

    Tambi茅n necesitaremos instalar la herramienta AWS CLI para interactuar con nuestros recursos de AWS desde nuestras m谩quinas. Las instrucciones para instalar la herramienta AWS CLI en varias plataformas se pueden encontrar aqu铆 .

    Con la herramienta AWS CLI en su lugar, podemos ir a la Consola de AWS y debajo de nuestro men煤 desplegable de perfil hay una secci贸n llamada “Mis credenciales de seguridad”. Aqu铆 podremos crear credenciales que se utilizar谩n al interactuar con la consola de AWS.

    Estas credenciales tambi茅n ser谩n utilizadas por la herramienta CLI de Amazon, que configuraremos ejecutando:

    $ aws configure
    

    Obtendremos un mensaje para llenar en nuestras Access Key ID, Secret Access Keyy las regiones predeterminadas y formatos de salida. Los dos 煤ltimos son opcionales pero necesitaremos la clave de acceso y el secreto que obtuvimos del tablero de la consola de AWS.

    Con nuestra cuenta de AWS en funcionamiento, y la AWS CLI configurada, podemos configurar nuestro AWS Simple Queue Service navegando a la p谩gina de inicio de SQS .

    Como podemos ver en la siguiente captura de pantalla, despu茅s de especificar nuestro nombre de cola, se nodeshop.fifonos presentan dos opciones de cola:

    Tenemos la opci贸n de elegir entre una Cola Est谩ndar o una Cola FIFO. Una cola est谩ndar no mantiene el orden de los mensajes que recibe y es m谩s adecuada para proyectos que priorizan el rendimiento sobre el orden de los eventos.

    Una cola FIFO, por otro lado, mantiene el orden de los mensajes tal como se reciben y tambi茅n se recuperan en el mismo orden primero en entrar, primero en salir.

    Dado que estaremos construyendo una mini plataforma de compras, es importante mantener el orden de las solicitudes ya que esperamos vender art铆culos a las personas en el orden de sus compras. Una vez que hemos elegido el tipo de cola que requerimos, podemos modificar alguna configuraci贸n adicional de nuestra cola:

    Podemos configurar el tiempo antes de que un mensaje se elimine autom谩ticamente de una cola y el tama帽o de un mensaje, entre otras opciones. Por ahora, configuraremos nuestra cola FIFO usando los valores predeterminados. Con nuestra cola lista, ahora podemos crear nuestras API Node.js que leer谩n y escribir谩n en nuestra cola FIFO de Amazon SQS.

    Configuraci贸n de Node.js y NPM

    La instrucci贸n para establecer Node.js en m煤ltiples plataformas se puede encontrar aqu铆 en la p谩gina web oficial de Node.js . Node Package Manager (NPM) se env铆a con Node.js y podemos verificar nuestra instalaci贸n de la siguiente manera:

    # Node.js version
    $ node -v
    v12.12.0
    
    # NPM version
    $ npm -v
    6.11.3
    

    El siguiente paso es configurar nuestras carpetas de la siguiente manera:

    # create folder and move into it
    $ mkdir nodeshop_apis && cd $_
    
    # create the orders and emails services folders
    $ mkdir orderssvc emailssvc
    

    Configuraci贸n de las API de node

    ordersPrimero crearemos el servicio ya que es el que recibe los pedidos de los usuarios y publica la informaci贸n en nuestra cola. Nuestro emailsservicio luego leer谩 de la cola y enviar谩 los correos electr贸nicos.

    Inicializaremos un proyecto Node.js e instalaremos el marco Express.js , que usaremos para construir nuestra API minimalista. Tambi茅n instalaremos el middleware body-parser para manejar nuestros datos de solicitud por nosotros y tambi茅n validarlos.

    Para lograr esto en nuestra carpeta ra铆z:

    # initialize node project
    $ npm init
    
    # install express and body-parser
    $ npm install express body-parser --save
    

    Una vez body-parserinstalados Express y , se a帽adir谩n autom谩ticamente a la secci贸n de dependencias de nuestro package.jsonarchivo gracias a la --saveopci贸n.

    Dado que tendremos m煤ltiples servicios que se ejecutar谩n al mismo tiempo, tambi茅n instalaremos el paquete npm-run-all para ayudarnos a iniciar todos nuestros servicios al mismo tiempo y no tener que ejecutar comandos en m煤ltiples Windows de terminal:

    $ npm install npm-run-all --save
    

    Con npm-run-allinstalado, ahora modifiquemos la scriptsentrada en nuestro package.jsonarchivo para incluir los comandos para iniciar nuestros servicios y un comando para ejecutarlos todos:

    {
      // Truncated for brevity...
      "scripts": {
        "start-orders-svc": "node ./orderssvc/index.js 8081",
        "start-emails-svc": "node ./emailssvc/index.js",
        "start": "npm-run-all -p -r start-orders-svc"
      },
      // ...
    }
    

    Agregaremos los comandos start-orders-svcy start-emails-svcpara ejecutar nuestros servicios ordersy emailsrespectivamente. Luego configuraremos el startcomando para ejecutarlos usando npm-run-all.

    Con esta configuraci贸n, ejecutar todos nuestros servicios ser谩 tan f谩cil como ejecutar el siguiente comando:

    $ npm start
    

    Podemos crear nuestra ordersAPI en el index.jsarchivo de la siguiente manera:

    const express = require('express');
    const bodyParser = require('body-parser');
    
    const port = process.argv.slice(2)[0];
    const app = express();
    
    app.use(bodyParser.json());
    
    app.get('/index', (req, res) => {
        res.send("Welcome to NodeShop Orders.")
    });
    
    console.log(`Orders service listening on port ${port}`);
    app.listen(port);
    

    Despu茅s de agregar las bibliotecas requeridas a nuestro Express app, el punto final “/ index” responder谩 simplemente enviando un mensaje de bienvenida. Finalmente, la API escuchar谩 en un puerto que especificaremos al iniciarlo.

    Iniciaremos la aplicaci贸n ejecutando el npm startcomando e interactuaremos con nuestras API utilizando la aplicaci贸n Postman :

    Implementaremos el emailsservicio m谩s adelante. Por ahora, nuestro ordersservicio est谩 configurado y ahora podemos implementar nuestra l贸gica comercial.

    Implementaci贸n: Servicio de pedidos

    Para implementar nuestra l贸gica comercial, comenzaremos con el ordersservicio que recibir谩 nuestros pedidos y los escribiremos en nuestra cola de Amazon SQS.

    Lo lograremos mediante la introducci贸n de una nueva ruta y controlador para manejar la entrada de pedidos del usuario final y enviar los datos del pedido a nuestra cola de Amazon SQS.

    Antes de implementar el controlador, necesitaremos instalar el SDK de Amazon para Node.js:

    $ npm install aws-sdk --save
    

    Nuestro nuevo punto de enlace “/ order” recibir谩 una carga 煤til que contiene los datos del pedido y lo enviar谩 a nuestra cola de SQS mediante el SDK de AWS:

    // ./orderssvc/index.js
    
    //
    // Code removed for brevity...
    //
    
    // Import the AWS SDK
    const AWS = require('aws-sdk');
    
    // Configure the region
    AWS.config.update({region: 'us-east-1'});
    
    // Create an SQS service object
    const sqs = new AWS.SQS({apiVersion: '2012-11-05'});
    const queueUrl = "SQS_QUEUE_URL";
    
    // the new endpoint
    app.post('/order', (req, res) => {
    
        let orderData = {
            'userEmail': req.body['userEmail'],
            'itemName': req.body['itemName'],
            'itemPrice': req.body['itemPrice'],
            'itemsQuantity': req.body['itemsQuantity']
        }
    
        let sqsOrderData = {
            MessageAttributes: {
              "userEmail": {
                DataType: "String",
                StringValue: orderData.userEmail
              },
              "itemName": {
                DataType: "String",
                StringValue: orderData.itemName
              },
              "itemPrice": {
                DataType: "Number",
                StringValue: orderData.itemPrice
              },
              "itemsQuantity": {
                DataType: "Number",
                StringValue: orderData.itemsQuantity
              }
            },
            MessageBody: JSON.stringify(orderData),
            MessageDeduplicationId: req.body['userEmail'],
            MessageGroupId: "UserOrders",
            QueueUrl: queueUrl
        };
    
        // Send the order data to the SQS queue
        let sendSqsMessage = sqs.sendMessage(sqsOrderData).promise();
    
        sendSqsMessage.then((data) => {
            console.log(`OrdersSvc | SUCCESS: ${data.MessageId}`);
            res.send("Thank you for your order. Check you inbox for the confirmation email.");
        }).catch((err) => {
            console.log(`OrdersSvc | ERROR: ${err}`);
    
            // Send email to emails API
            res.send("We ran into an error. Please try again.");
        });
    });
    

    El AWS SDK requiere que creemos un objeto de carga 煤til especificando los datos que estamos enviando a la cola, en nuestro caso lo definimos como sqsOrderData.

    Luego pasamos este objeto a la sendMessage()funci贸n que enviar谩 nuestro mensaje a la cola usando las credenciales que usamos para configurar la AWS CLI. Finalmente, esperamos la respuesta y notificamos al usuario que su pedido ha sido recibido con 茅xito y que debe verificar el correo electr贸nico de confirmaci贸n.

    Para probar el ordersservicio, ejecutamos el comando npm starty enviamos la siguiente carga 煤til a localhost:8081/order:

    {
        "itemName": "Phone case",
        "itemPrice": "10",
        "userEmail": "[email聽protected]",
        "itemsQuantity": "2"
    }
    

    Esto enviar谩 nuestro pedido al ordersservicio, desde donde se enviar谩 el mensaje a nuestra cola de SQS. Podemos ver el pedido en la cola de SQS a trav茅s de la consola de AWS, como se muestra:

    Nuestro ordersservicio ha podido recibir el pedido de un usuario y enviar con 茅xito los datos a nuestra cola en el Servicio de Cola Simple.

    Implementaci贸n: Servicio de correos electr贸nicos

    Nuestro ordersservicio est谩 listo y ya est谩 recibiendo pedidos de los usuarios. El emailsservicio se encargar谩 de leer los mensajes almacenados en la cola y enviar correos electr贸nicos de confirmaci贸n a los usuarios. Este servicio no es notificado cuando se realizan pedidos y, por lo tanto, debe seguir revisando la cola para ver si hay nuevos pedidos.

    Para asegurarnos de que nuestro emailsservicio comprueba continuamente si hay nuevos pedidos, utilizaremos la sqs-consumerbiblioteca que comprobar谩 de forma continua y peri贸dica si hay nuevos pedidos y enviar谩 los correos electr贸nicos a los usuarios. sqs-consumertambi茅n eliminar谩 los mensajes de la cola una vez que los haya le铆do correctamente de la cola.

    Comenzaremos instalando la sqs-consumerbiblioteca ejecutando el siguiente comando:

    $ npm install sqs-consumer --save
    

    Ahora podemos implementar el emailsservicio de la siguiente manera:

    const AWS = require('aws-sdk');
    const { Consumer } = require('sqs-consumer');
    
    // Configure the region
    AWS.config.update({region: 'us-east-1'});
    
    const queueUrl = "SQS_QUEUE_URL";
    
    // Configure Nodemailer to user Gmail
    let transport = nodemailer.createTransport({
        host: 'smtp.googlemail.com',
        port: 587,
        auth: {
            user: 'Email address',
            pass: 'Password'
        }
    });
    
    function sendMail(message) {
        let sqsMessage = JSON.parse(message.Body);
        const emailMessage = {
            from: 'sender_email_adress',    // Sender address
            to: sqsMessage.userEmail,     // Recipient address
            subject: 'Order Received | NodeShop',    // Subject line
            html: `<p>Hi ${sqsMessage.userEmail}.</p. <p>Your order of ${sqsMessage.itemsQuantity} ${sqsMessage.itemName} has been received and is being processed.</p> <p> Thank you for shopping with us! </p>` // Plain text body
        };
    
        transport.sendMail(emailMessage, (err, info) => {
            if (err) {
                console.log(`EmailsSvc | ERROR: ${err}`)
            } else {
                console.log(`EmailsSvc | INFO: ${info}`);
            }
        });
    }
    
    // Create our consumer
    const app = Consumer.create({
        queueUrl: queueUrl,
        handleMessage: async (message) => {
            sendMail(message);
        },
        sqs: new AWS.SQS()
    });
    
    app.on('error', (err) => {
        console.error(err.message);
    });
    
    app.on('processing_error', (err) => {
        console.error(err.message);
    });
    
    console.log('Emails service is running');
    app.start();
    

    Crearemos una nueva sqs-consumeraplicaci贸n usando la Consumer.create()funci贸n y proporcionaremos la URL de consulta y la funci贸n para manejar los mensajes extra铆dos de la cola de SQS.

    En nuestro caso, la funci贸n sendMail()tomar谩 el mensaje obtenido de la cola, extraer谩 los detalles del pedido del usuario y luego enviar谩 un correo electr贸nico al usuario que usa Nodemailer. Consulte nuestro art铆culo sobre el env铆o de correos electr贸nicos en Node.js, si desea obtener m谩s informaci贸n.

    Nuestro emailsservicio ya est谩 listo. Para integrarlo a nuestro script de ejecuci贸n, simplemente modificaremos la scriptsopci贸n en nuestro package.json:

    {
      // Truncated for brevity...
      "scripts": {
        "start-orders-svc": "node ./orderssvc/index.js 8081",
        "start-emails-svc": "node ./emailssvc/index.js",
        // Update this line
        "start": "npm-run-all -p -r start-orders-svc start-emails-svc"
      },
      // ...
    }
    

    Cuando enviamos un nuevo pedido a trav茅s del ordersservicio, recibimos el siguiente correo electr贸nico en nuestra bandeja de entrada:

    Conclusi贸n

    En esta publicaci贸n, usamos Node.js y Express para crear una API que estaba destinada a recibir los pedidos de los usuarios y publicar los detalles del pedido en nuestra cola de SQS en AWS. Luego, creamos otro servicio para buscar los mensajes publicados en la cola y enviar correos electr贸nicos de confirmaci贸n a los usuarios que publicaron los pedidos.

    Separamos la l贸gica de pedidos de la l贸gica de administraci贸n de correo electr贸nico y reunimos los dos servicios mediante un sistema de cola de mensajes. De esta manera, nuestro ordersservicio puede manejar la realizaci贸n de pedidos mientras el emailsservicio env铆a los correos electr贸nicos a los usuarios.

    El c贸digo fuente de este proyecto est谩 disponible aqu铆 en GitHub .

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *