Tareas lentas en el ciclo petición-respuesta
Imagina que al registrarse un usuario quieres enviarle un email de bienvenida. Enviar el email tarda 2 segundos. Si lo haces dentro del handler, el usuario espera esos 2 segundos a que cargue la página. Peor aún: procesar un vídeo o generar un informe puede tardar minutos.
La regla: saca las tareas lentas del ciclo petición-respuesta. Responde rápido al usuario y haz el trabajo pesado en segundo plano.
Colas de mensajes
Una cola de mensajes desacopla a quien pide el trabajo de quien lo hace:
- El productor (tu handler) encola un trabajo y responde al instante.
- El consumidor (un proceso aparte, el worker) saca trabajos de la cola y los procesa a su ritmo.
- Un broker (intermediario) guarda la cola: RabbitMQ, o Redis con BullMQ en el mundo Node.
// Productor: encola y responde ya
await cola.add("enviarEmail", { para: "ana@mail.com" });
res.status(202).json({ estado: "en proceso" });
// Consumidor (worker): procesa en segundo plano
worker.process("enviarEmail", async (trabajo) => {
await enviarEmail(trabajo.datos.para);
});
Reintentos
Si un trabajo falla (la API de email no responde), la cola puede reintentar automáticamente unas cuantas veces antes de mandarlo a una dead-letter queue para revisión manual. Esto da resiliencia ante fallos transitorios.
Idempotencia
Si un trabajo se reintenta, podría ejecutarse más de una vez. Una operación es idempotente cuando ejecutarla N veces produce el mismo efecto que ejecutarla una vez. "Fijar el saldo a 100€" es idempotente; "sumar 100€" no lo es (se duplicaría en cada reintento).
La técnica habitual: dar a cada trabajo un id único y registrar los ya procesados, de modo que un reintento del mismo id no vuelva a aplicar el efecto.