En sistemas modernos, gestionar múltiples tareas en paralelo de manera eficiente es clave para mantener una buena escalabilidad y rendimiento. Las colas de trabajo (Job Queues) permiten procesar tareas largas o repetitivas en segundo plano, lo que libera a los sistemas de tener que esperar a que estas tareas terminen. En este artículo, veremos cómo gestionar colas de trabajo en Node.js utilizando Bull, una biblioteca muy eficiente basada en Redis.
Bull es una biblioteca de colas de trabajo para Node.js, construida sobre Redis. Proporciona un sistema robusto para manejar tareas en segundo plano y soporta características avanzadas como:
Antes de comenzar, asegúrate de tener lo siguiente:
Puedes instalar Redis en tu entorno local o utilizar un servicio como Redis Cloud.
Primero, vamos a instalar Bull y Redis en nuestro proyecto.
npm install bull
Bull se basa en Redis para manejar el almacenamiento de las tareas, por lo que debes asegurarte de que Redis está corriendo. Puedes lanzar Redis localmente con:
redis-server
Bull ofrece una API simple para manejar colas de trabajo. Vamos a ver cómo crear y gestionar colas con un ejemplo práctico.
Primero, vamos a crear una cola simple que procesará tareas. Edita tu archivo index.js
o app.js
para incluir lo siguiente:
const Queue = require('bull');
// Crear una cola llamada "email"
const emailQueue = new Queue('email', {
redis: {
host: '127.0.0.1',
port: 6379
}
});
Aquí hemos creado una cola llamada email
. Bull por defecto conectará a Redis en localhost
en el puerto 6379
, pero puedes cambiar los parámetros de conexión si tu Redis está en otro lugar.
Los trabajos son las tareas que queremos procesar. Vamos a añadir un trabajo a nuestra cola email
que simula el envío de un correo electrónico.
// Añadir un trabajo a la cola "email"
emailQueue.add({
recipient: 'usuario@example.com',
subject: 'Bienvenido a nuestro servicio',
body: 'Gracias por registrarte en nuestro servicio.'
});
Cada trabajo contiene un payload (carga útil) con los datos necesarios para realizar la tarea. En este caso, los datos son el destinatario, el asunto y el cuerpo del correo electrónico.
Ahora que hemos añadido trabajos a la cola, necesitamos definir cómo se procesarán. Esto se hace utilizando la función process()
de Bull, que recibe una callback encargada de manejar cada trabajo.
emailQueue.process(async (job) => {
const { recipient, subject, body } = job.data;
console.log(`Enviando correo a: ${recipient}`);
console.log(`Asunto: ${subject}`);
console.log(`Mensaje: ${body}`);
// Simular envío de correo electrónico
await sendEmail(recipient, subject, body);
console.log('Correo enviado con éxito');
});
// Función ficticia para simular el envío de un correo electrónico
async function sendEmail(to, subject, body) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 1000);
});
}
En este ejemplo, cada vez que se añade un nuevo trabajo a la cola, Bull lo procesa llamando a la función sendEmail()
, la cual simula el envío de un correo electrónico con un retardo de 1 segundo.
Es común que una tarea falle y deba reintentarse. Bull permite manejar errores fácilmente y configurar reintentos automáticos en caso de fallos.
emailQueue.process(async (job) => {
try {
const { recipient, subject, body } = job.data;
console.log(`Enviando correo a: ${recipient}`);
// Simular error en el envío del correo
if (Math.random() > 0.5) {
throw new Error('Error al enviar correo');
}
await sendEmail(recipient, subject, body);
console.log('Correo enviado con éxito');
} catch (error) {
console.error(`Error procesando trabajo: ${error.message}`);
throw error; // El trabajo será reintentado automáticamente
}
});
Además, puedes configurar el número de reintentos permitidos para cada trabajo:
emailQueue.add({
recipient: 'usuario@example.com',
subject: 'Bienvenido a nuestro servicio',
body: 'Gracias por registrarte en nuestro servicio.'
}, {
attempts: 3, // Reintentar 3 veces en caso de fallo
backoff: 5000 // Tiempo de espera entre reintentos (5 segundos)
});
Bull también permite establecer prioridades en los trabajos para asegurarte de que ciertos trabajos sean procesados antes que otros.
emailQueue.add({
recipient: 'vip@example.com',
subject: 'Bienvenido, usuario VIP',
body: 'Gracias por unirte como usuario VIP.'
}, {
priority: 1 // Mayor prioridad (1 es la más alta)
});
emailQueue.add({
recipient: 'usuario@example.com',
subject: 'Bienvenido a nuestro servicio',
body: 'Gracias por registrarte.'
}, {
priority: 5 // Menor prioridad
});
Además, puedes retrasar el procesamiento de un trabajo hasta un momento específico en el futuro:
emailQueue.add({
recipient: 'usuario_lento@example.com',
subject: 'Correo con retraso',
body: 'Este correo se envía después de 10 segundos.'
}, {
delay: 10000 // Retrasar el trabajo 10 segundos
});
Una característica importante de Bull es su capacidad de monitoreo de trabajos. Puedes capturar eventos como cuando un trabajo comienza, se completa, o falla.
emailQueue.on('completed', (job) => {
console.log(`Trabajo completado: ${job.id}`);
});
emailQueue.on('failed', (job, err) => {
console.error(`Trabajo fallido: ${job.id}, Error: ${err.message}`);
});
Además, existe una herramienta visual llamada BullBoard que puedes usar para monitorear tus colas en una interfaz gráfica.
Bull también permite programar tareas recurrentes, lo que es útil para tareas como enviar correos periódicos o realizar mantenimientos.
emailQueue.add({
recipient: 'recordatorio@example.com',
subject: 'Recordatorio semanal',
body: 'Este es tu recordatorio semanal.'
}, {
repeat: { cron: '0 9 * * 1' } // Cada lunes a las 9:00 AM
});
En algunos casos, puede ser útil pausar temporalmente el procesamiento de trabajos y luego reanudarlo.
// Pausar la cola
emailQueue.pause().then(() => {
console.log('La cola ha sido pausada.');
});
// Reanudar la cola
emailQueue.resume().then(() => {
console.log('La cola ha sido reanudada.');
});
En este artículo, hemos explorado cómo crear y gestionar colas de trabajo en Node.js utilizando Bull. Hemos cubierto desde la creación básica de una cola hasta características más avanzadas como reintentos, prioridades y tareas recurrentes. Bull es una poderosa herramienta que simplifica el procesamiento de tareas en segundo plano, permitiendo a tus aplicaciones Node.js escalar y manejar cargas de trabajo intensivas de manera eficiente.
Recuerda que Bull está basado en Redis, por lo que es importante asegurarse de que Redis esté correctamente configurado y dimensionado para la cantidad de trabajos que manejarás. ¡Con estas bases, puedes construir sistemas robustos y escalables para tus aplicaciones Node.js!
Jorge García
Fullstack developer