main content
< Volver a blog sobre aplicaciones móviles

Colas y procesamiento asíncrono en tu web a medida

Cómo implementar un sistema de colas y procesamiento asíncrono en tu aplicación web a medida

Toda aplicación web que pasa de prototipo a producto real acaba chocando con el mismo muro: hay operaciones que tardan demasiado para ejecutarse dentro de un ciclo petición-respuesta HTTP. Enviar un email de confirmación, generar un PDF, redimensionar imágenes, sincronizar datos con un ERP externo... Todas comparten algo: no necesitan resolverse antes de que el servidor conteste al navegador.

Y sin embargo, he visto proyectos donde todo se procesa en línea. El usuario pulsa "Crear pedido" y se queda mirando un spinner durante 10 segundos mientras el backend genera la factura, manda el correo, actualiza inventario y notifica al sistema de logística. Uno por uno. En serie. El resultado es una experiencia frustrante y un servidor que se ahoga.

La solución lleva años consolidada en la industria: colas de mensajes con workers de procesamiento asíncrono. Vamos a ver cómo funciona, qué tecnologías tienes disponibles y qué patrones aplicamos en proyectos reales.

Por qué el procesamiento síncrono deja de escalar

Cada petición HTTP ocupa un hilo (o una conexión en modelos event-loop como Node.js) hasta que se completa. Google publicó en su informe Core Web Vitals de 2024 un dato contundente: el 53 % de los usuarios moviles abandona una pagina que tarda mas de tres segundos. Tres segundos. Y si tu endpoint necesita ademas generar un PDF y llamar a dos APIs externas, los 8-12 segundos llegan con facilidad.

Pero el problema no es solo la experiencia de usuario. Piensa en los numeros. Un servidor con 200 hilos activos procesando tareas sincronas de 5 segundos de media atiende 40 peticiones por segundo. Si sacas las tareas pesadas fuera del ciclo HTTP y el endpoint responde en 200 ms, esa misma maquina pasa a servir 1000 peticiones por segundo. Un salto de 25x en capacidad. Con el mismo hardware.

Arquitectura general: tres piezas que encajan

Un sistema de colas tiene tres componentes. Ni mas ni menos.

Productor (Publisher)

Es tu aplicacion web. El controlador del endpoint escribe un mensaje JSON en la cola con los datos necesarios (ID del pedido, tipo de tarea, parametros) y devuelve un HTTP 202 Accepted al cliente. Rapido, limpio, sin bloqueos.

Broker de mensajes (Message Queue)

El intermediario que almacena los mensajes hasta que alguien los procesa. Garantiza que no se pierdan si un worker cae, que se entreguen en orden y que se repartan entre multiples workers. Los tres brokers dominantes son RabbitMQ, Redis (con sus modulos de streaming) y Apache Kafka.

Consumidor (Worker)

Un proceso independiente que escucha la cola, extrae mensajes y ejecuta la tarea. Puede correr en la misma maquina o en servidores dedicados. Y aqui viene la gracia: escala horizontalmente. Si la cola crece, lanzas mas workers. Asi de simple.

RabbitMQ, Redis o Kafka: cual te conviene

Esta es la pregunta que mas nos hacen. La respuesta corta: depende de tu volumen, tu complejidad y tus requisitos de durabilidad.

RabbitMQ

Implementa el protocolo AMQP 0.9.1 y es el broker mas maduro para colas de trabajo clasicas. Soporta exchanges (direct, fanout, topic, headers), lo que permite enrutar mensajes de formas muy flexibles. Tiene confirmaciones de entrega, reintentos automaticos y dead-letter queues para mensajes que fallan una y otra vez.

En el mercado espanol, RabbitMQ es la opcion mas desplegada en proyectos de tamano medio. Su plugin de gestion web permite ver las colas en tiempo real, y la integracion con frameworks como Laravel (Horizon), Django (Celery) o Spring Boot es nativa. Un servidor con 4 GB de RAM mueve entre 10 000 y 50 000 mensajes por segundo. Para la gran mayoria de aplicaciones empresariales, sobra.

Mejor para: enrutamiento complejo, garantias de entrega estrictas y ecosistema maduro de plugins.

Redis con Streams y BullMQ

Redis, que todo el mundo conoce como cache en memoria, incorporo Streams en la version 5.0. Con BullMQ (Node.js) o RQ (Python), se convierte en un broker de colas ligero y extremadamente rapido. Latencia de publicacion: 0,1 ms, frente a los 1-2 ms de RabbitMQ.

La ventaja mas practica es que muchos proyectos ya tienen Redis desplegado como cache. Reutilizarlo para colas te ahorra un componente en la infraestructura. BullMQ ofrece rate limiting, prioridades, jobs programados tipo cron y dashboards con Bull Board.

Mejor para: proyectos Node.js de tamano pequeno a medio que ya usan Redis y donde la simplicidad operativa pesa mas que la durabilidad estricta.

Apache Kafka

Kafka no es una cola de mensajes. Es una plataforma de streaming distribuido. Los mensajes se almacenan en un log particionado e inmutable, con retencion configurable (dias, semanas o indefinida). Multiples consumidores pueden leer el mismo stream de forma independiente, algo que en una cola tradicional no existe porque el mensaje desaparece al consumirse.

LinkedIn, que lo creo, procesa mas de 7 billones de mensajes diarios. En Espana, Kafka encaja en plataformas de ecommerce con millones de transacciones, sistemas IoT o arquitecturas de microservicios donde varios servicios reaccionan al mismo evento.

Mejor para: alto volumen (>100 000 mensajes/segundo), arquitecturas event-driven con multiples consumidores, y escenarios donde el historial de eventos tiene valor analitico.

Patrones que funcionan en la practica

Fire-and-forget con reintentos

El productor publica y se desentiende. El worker procesa la tarea; si falla, el broker la reintenta con backoff exponencial. Tras N intentos fallidos, el mensaje va a una dead-letter queue para inspeccion manual.

Endpoint HTTP -> Publica mensaje -> Responde 202
                      |
               Cola principal
                      |
               Worker intenta procesar
                  | (fallo)
               Reintento con backoff (1s, 5s, 30s, 120s)
                  | (fallo persistente)
               Dead-letter queue -> Alerta al equipo

Este patron cubre el 80 % de los casos: envio de emails, generacion de documentos, sincronizacion con APIs externas, procesamiento de imagenes.

Request-reply asincrono

A veces el cliente necesita el resultado, pero no puede quedarse esperando. El productor genera un job ID, lo devuelve al cliente, y el worker almacena el resultado en Redis o en base de datos. El cliente consulta el estado por polling o WebSocket.

Perfecto para informes complejos que tardan minutos, exportaciones masivas de datos o importaciones de CSV con miles de registros.

Pipeline de procesamiento

Varias tareas encadenadas: el output de una alimenta la siguiente. Un upload de imagen pasa por validacion, redimensionado, marca de agua, compresion y almacenamiento en S3. Cada paso es un worker que publica en la cola del paso siguiente. RabbitMQ gestiona esto con exchanges topic. Kafka lo hace de forma natural con Kafka Streams.

Lo que puede salir mal (y como evitarlo)

Idempotencia

Un worker puede recibir el mismo mensaje dos veces. Pasa, por ejemplo, si el acknowledge se pierde por un corte de red. Las tareas deben ser idempotentes: ejecutar la misma dos veces con los mismos parametros produce el mismo resultado, sin duplicar efectos. En la practica, una tabla de jobs procesados donde verificas el ID del mensaje antes de ejecutar resuelve el problema.

Monitorizacion

Sin visibilidad sobre las colas, los problemas se detectan cuando ya duelen. Las metricas que necesitas: profundidad de cola (mensajes pendientes), tasa de procesamiento (mensajes/segundo), tasa de errores y latencia de procesamiento. Prometheus con Grafana o el management plugin de RabbitMQ te dan esa visibilidad.

Persistencia

En RabbitMQ, declara colas y mensajes como "durable" y "persistent" o perderas datos en un reinicio. En Redis, activa AOF o RDB snapshots, aunque no garantiza durabilidad al 100 % por defecto. Kafka, por diseno, replica cada particion en multiples brokers: la mejor durabilidad de los tres.

Escalado de workers

La belleza de esta arquitectura es que escalar es trivial. En Kubernetes, un Horizontal Pod Autoscaler escala los pods de workers segun la profundidad de la cola. Mas de 1000 mensajes pendientes, mas workers. Menos de 100, se reducen. Automatico.

Errores clasicos que vemos en auditorias

He visto proyectos que usan la base de datos relacional como cola: una tabla jobs con polling constante. Funciona con 10 mensajes, pero a medida que crece el volumen la contención devora el rendimiento. Otro error habitual: no implementar dead-letter queues. Los mensajes fallidos se reintentan hasta el infinito, consumiendo recursos sin producir nada.

Y hay uno mas sutil: publicar mensajes dentro de una transaccion de base de datos sin el patron transactional outbox. El riesgo es que el mensaje se publique pero la transaccion se revierta. O al reves. El resultado son inconsistencias dificiles de rastrear.

Cuando merece la pena dar el paso

No todos los proyectos necesitan colas desde el dia uno. La regla que aplicamos es practica: si tu aplicacion tiene mas de tres operaciones que tardan mas de un segundo y afectan a la experiencia del usuario, vale la pena. Por debajo de ese umbral, unos jobs en background con threads pueden ser suficientes.

Si estas planificando una aplicacion web a medida y necesitas orientacion sobre que arquitectura de procesamiento asincrono encaja mejor, nuestro equipo tecnico puede ayudarte a disenar la solucion correcta.

Para cerrar

Un sistema de colas y procesamiento asincrono es la pieza que permite a tu aplicacion web escalar de verdad. RabbitMQ, Redis o Kafka: cada uno tiene su sitio dependiendo del volumen, la complejidad del enrutamiento y la durabilidad que necesites. Lo que no cambia es el principio de fondo: sacar las tareas pesadas del ciclo HTTP mejora la experiencia del usuario, estabiliza el sistema y te permite crecer anadiendo workers en vez de reescribiendo codigo. Montarlo desde el principio sale mucho mas barato que refactorizar una aplicacion sincrona que ya ha tocado techo.

Contacta con nosotros
Fila 1