BullMQ - colas en nodejs para proyectos de alto rendimiento

BullMQ - colas en nodejs para proyectos de alto rendimiento

La gestión eficiente de colas y tareas en aplicaciones nodejs es esencial para garantizar un rendimiento fluido y una experiencia del usuario sin problemas, estas herramientas de gestión de colas permiten a las aplicaciones procesar tareas de manera asíncrona, mejorando la capacidad de respuesta y la eficiencia, actualmente existen muchas aplicaciones, pero particularmente para nodejs existe una llamada BullMQ, una biblioteca diseñada específicamente para aplicaciones nodejs que aprovecha Redis para su funcionamiento, haré una breve comparación con RabbitMQ y trataré de explicar las ventajas de BullMQ, su integración con nodejs y Redis, y porque no? hasta un ejemplo sencillo para que comprendas cóomo se utiliza.

¿Qué es BullMQ y cómo puede mejorar tu aplicación?

BullMQ es una biblioteca de gestión de colas y tareas que se enfoca en la simplicidad y el rendimiento en aplicaciones nodejs, esta libraría permite el procesamiento asíncrono de tareas, BullMQ mejora la capacidad de respuesta de las aplicaciones y evita bloqueos al realizar operaciones que pueden ser lentas, como enviar correos electrónicos, generar archivos, procesar imágenes o realizar cálculos complejos (ya lo sé, todos estos puntos son debatibles y quizás nodejs no se la mejor opción para realizarlos).

Ventajas de BullMQ:

  • Rendimiento: BullMQ está diseñado específicamente para nodejs y utiliza Redis para el almacenamiento de colas, lo que le permite ofrecer un procesamiento rápido y eficiente de tareas asincrónicas.

  • Priorización y retraso: Puedes priorizar tareas y retrasar su ejecución para manejar cargas de trabajo variables y optimizar recursos.

  • Manejo de Errores y Reintentos: BullMQ incluye mecanismos para manejar errores y reintentos de tareas fallidas, asegurando que las operaciones importantes se completen incluso en situaciones inesperadas.

  • Procesamiento Asíncrono de Tareas: Al utilizar BullMQ, puedes realizar operaciones de larga duración, sin bloquear el hilo actual en el que funciona tu aplicación, ayudándote a mejorar los tiempos de respuesta.

Comparación con RabbitMQ:

RabbitMQ es una herramienta versátil con capacidades avanzadas de enrutamiento y suscripción, sin embargo, en casos de uso más simples, puede tener una sobrecarga y latencia ligeramente mayores en comparación con BullMQ.

  • Escalabilidad y Clusters: BullMQ destaca con su soporte nativo para clusters y la utilización de Redis como backend, ofreciendo una opción sencilla para escalabilidad horizontal.

  • Rendimiento en sistemas complejos: RabbitMQ es ideal para sistemas complejos con alto volumen de mensajes y alta disponibilidad.

  • Conexion entre sistemas con diferentes lenguajes: Una ventaja bastante obvia de RabbitMQ es que cuando tienes muchos servicios en los que utilizas diferentes lenguajes de programación, no se discute que BullMQ no sea una opción ya que solo funciona para nodejs.

Ejemplo práctico: Envío asíncrono de emails

Supongamos que estás desarrollando una aplicación de comercio electrónico en nodejs y quieres mejorar la experiencia del usuario al enviar correos electrónicos de confirmación de pedidos de manera asíncrona, sin ralentizar la interacción del usuario, entonces utilizando BullMQ podría verse de la siguiente manera:

const { Queue, Worker } = require('bullmq');
const { Redis } = require('ioredis');

// Configuración de conexión a Redis
const connection = new Redis();

// crear la cola
const emailQueue = new Queue('email-tasks', { connection });

// agregar un worker a la cola existente
const emailWorker = new Worker('email-tasks', async job => {
  // Lógica en general, quizás algo como
  // handlebar para el render del email
  // nodemailer para el envío
  // etc...
  console.log(`Enviando correo a: ${job.data.destinatario}`);
});

// agregar la tarea de envío de correo a la cola
await emailQueue.add('task-email', { destinatario: '[email protected]', contenido: '¡Gracias por tu pedido!' });

Donde:

email-tasks: Se refiere al nombre de la cola de tareas, dicho más claro, una cola es un lugar donde se almacenan las tareas para su procesamiento posterior. Cada tarea en la cola puede tener una etiqueta o nombre que ayude a identificar la naturaleza de la tarea que se debe realizar.

enviar-correo: Es un tipo de tarea específica que se agrega a la cola. En este contexto, representa la acción de enviar un correo electrónico. Cada tarea puede llevar consigo una serie de datos o información necesaria para realizar esa tarea en particular.

Y algunas anotaciones importantes sobre el uso de los tasks es que tener un "task" o nombre de tarea sirve para identificar cada job o unidad de trabajo encolada.

Algunos usos:

  • Permite reconocer fácilmente el propósito de cada job sin necesidad de inspeccionar los datos. Por ejemplo, sabemos que "task-email" es para enviar emails.

  • Si tienes múltiples workers, puedes asignarlos a procesar jobs de ciertas tareas específicas. Por ejemplo, un worker sólo para "task-email".

  • Puedes consultar la cola para ver cuántos jobs hay de cierta tarea pendiente. Por ejemplo, cuántos "task-email" faltan por procesar.

  • Al momento de procesar el job, puedes tomar decisiones lógicas según la tarea. Por ejemplo, enviar el email si es "task-email", generar un PDF si es "task-generate-pdf", etc.

  • Permite identificar fácilmente jobs que fallen o causen errores, ya que tienen el nombre de tarea asociado.

Asignar un nombre de tarea a los jobs no es obligatorio pero permite manejarlos de una manera más organizada y personalizada dentro de la cola de trabajo, el nombre se puede usar tanto al encolar como al procesar los jobs.

Yo particularmente como regla general y en términos de escalabilidad para proyectos en los que se utilizan colas en nodejs, empiezo con BullQM, RedisMQ y finalmente con Kafka.

Happy coding! :D


Photo by Anderson Rian on Unsplash

Jack Fiallos

Jack Fiallos

Te gustó este artículo?