Curso exprés · No. 18
Cuando una parte de un sistema necesita que otra haga algo, la forma sencilla es llamarla y esperar una respuesta. La forma poderosa es dejar un mensaje en una queue y seguir adelante, dejando que el otro lado lo recoja cuando esté listo. Ese único cambio — de llamar y esperar a enviar un mensaje y continuar — es como los sistemas se mantienen rápidos, sobreviven a los fallos y escalan.
21 conceptos · un diagrama para cada uno · resumen al final
Para entender por qué existen las queues, primero hay que sentir el dolor de la alternativa sencilla: un servicio que llama a otro y lo espera. Funciona hasta el momento en que de verdad importa.
El mapa: 21 conceptos en seis grupos
Un mapa de metro: primero ves las líneas enteras, luego recorres estación por estación.
Primero el problema — por qué una llamada directa te falla. Después un capítulo por grupo: la queue (la idea en sí), los roles (quién escribe, quién lee, quién guarda), comandos y eventos (dos tipos de mensaje), los beneficios (por qué pagas) y las partes difíciles (qué se rompe). El último capítulo trata de cuándo usar una queue y cuándo no, e incluye un mapa de relaciones y un resumen.
Cómo leer cada concepto
Un pasaporte: los mismos campos para todos, así es fácil compararlos.
Cada concepto a partir de aquí tiene la misma forma: su nombre en inglés (apréndelo — es la palabra que verás en la documentación de los brokers y en las entrevistas), una imagen de la vida cotidiana, un diagrama y una ficha: problema, idea, ejemplo, coste y cómo se relaciona con otros conceptos. Al final: un mapa de relaciones y un resumen.
Synchronous Call — una llamada directa ata dos servicios entre sí
Telefonear a alguien y quedarte en la línea hasta que termine la tarea — no puedes colgar, no puedes hacer nada más, y si no contesta, te quedas atascado.
La forma obvia de que el servicio A consiga que el servicio B haga algo es una synchronous call: A pregunta y luego espera, conteniéndolo todo hasta que B responde. Esto los acopla estrechamente — la velocidad de A queda ahora secuestrada por la velocidad de B, y A no puede continuar hasta que B termine. Para una respuesta rápida eso está bien. Para un trabajo lento o pesado, A pasa el tiempo congelado, esperando a otro.
- Problema
- El que llama queda congelado hasta que el llamado responde.
- Idea
- Preguntar, esperar la respuesta y seguir. La forma más simple de hablar.
- Ejemplo
El servicio de pedidos llama por HTTP al servicio de precios y espera el precio antes de mostrar el carrito.
- Coste
Acoplamiento estrecho: la velocidad y la disponibilidad de A dependen de B.
- Relaciones
Su dolor lo cura una Message Queue; para respuestas instantáneas sigue siendo la mejor opción.
Failure Propagation — si el llamado está caído, el que llama se rompe
Llamar al almacén para confirmar un pedido y, como nadie contesta, negarte a aceptar cualquier pedido nuevo — una puerta cerrada bloquea toda la tienda.
El problema más profundo es el fallo. Si B está caído o sobrecargado cuando A llama, la petición de A también falla — el fallo se propaga directamente hacia arriba en la cadena. Un solo servicio lento o roto puede paralizar todo lo que depende de él, y un pico de tráfico hacia B arrastra a A consigo. El acoplamiento estrecho significa que la debilidad se extiende, y el sistema solo está tan disponible como su parte más frágil.
- Problema
El fallo de un servicio se convierte en el fallo de todos los que lo llaman.
- Idea
- Una cadena síncrona solo es tan disponible como su eslabón más débil.
- Ejemplo
El almacén no responde → los pedidos dan error → el pago deja de funcionar.
- Coste
- Un pico de tráfico hacia un servicio arrastra todo lo que tiene encima.
- Relaciones
Se cura con un búfer: una Message Queue da Resilience — un fallo se convierte en un retraso.
Background Work — cierto trabajo no debería bloquear al usuario
En una caja, pagas y te vas con tu recibo — no te quedas en la caja mientras empaquetan, envían y te mandan un correo. Las partes lentas ocurren después de que te marchas.
Mucho trabajo no necesita terminar antes de que el usuario reciba una respuesta — enviar el correo de confirmación, generar la factura, redimensionar la foto. Esto es background work (trabajo en segundo plano). Hacer que el usuario espere todo eso es lento e inútil. Quieres aceptar la petición, responder rápido y dejar que las partes lentas ocurran después. Una llamada directa no puede hacer eso; obliga a todos a esperar por todo.
- Problema
- El usuario espera trabajo del que su respuesta no depende.
- Idea
- Aceptar la petición, responder rápido y hacer las partes lentas después.
- Ejemplo
El pago pasó — recibo ya; el correo, la factura y el redimensionado de la foto, en segundo plano.
- Coste
- El resultado del trabajo en segundo plano no aparece al instante.
- Relaciones
- Se hace con una Message Queue y Asynchronous Processing.
Una llamada directa acopla dos servicios en el tiempo: el que llama espera y hereda la lentitud y los fallos del llamado. Para trabajo lento o no urgente, eso es una trampa.
La solución es dejar de llamar y empezar a enviar mensajes. Una queue es el búfer del medio que permite a un lado dejar trabajo y al otro recogerlo — desacoplándolos en el tiempo.
Message Queue — deja el mensaje y sigue adelante
Dejar un mensaje de voz en lugar de esperar al teléfono: dices lo que necesitas, cuelgas y sigues con tu día — lo atenderán cuando puedan.
En lugar de llamar a B y esperar, A escribe un mensaje que describe el trabajo y lo deja en una queue — una fila donde los mensajes esperan a ser procesados. A queda libre para continuar de inmediato; no le importa cuándo llegue B a ello. El mensaje es un pequeño paquete de «esto es lo que hay que hacer», entregado en lugar de ejecutado en el acto. Ese traspaso es toda la idea.
- Problema
- Una llamada directa mantiene al emisor en la línea.
- Idea
Describir el trabajo como un mensaje y ponerlo en una queue; el receptor lo recoge por su cuenta.
- Ejemplo
En lugar de llamar al servicio de correo — un mensaje
SendEmailcon el número de pedido, en una queue.- Coste
- Una pieza móvil nueva que hay que ejecutar y entender.
- Relaciones
Da Temporal Decoupling; la guarda un Broker; la leen los Consumers.
Temporal Decoupling — la queue es un búfer en el tiempo
Una bandeja de entrada en un escritorio: el trabajo se acumula en ella y se atiende con calma, así que una avalancha repentina de papeles no abruma a la persona — solo hace la bandeja más alta por un rato.
La queue se sitúa entre los dos lados como un búfer, guardando los mensajes hasta que se procesan. Esto los desacopla en el tiempo (temporal decoupling): el emisor y el receptor ya no tienen que ser rápidos, estar disponibles ni siquiera estar en marcha en el mismo momento. El trabajo producido en ráfagas puede consumirse de forma constante. La queue absorbe la diferencia entre la velocidad a la que llega el trabajo y la velocidad a la que se puede hacer.
- Problema
- Ambos lados deben estar vivos y ser rápidos en el mismo momento.
- Idea
Un búfer entre ellos: emisor y receptor trabajan cada uno a su propio tiempo.
- Ejemplo
Una ráfaga de pedidos se acumula en la queue y se procesa a un ritmo constante.
- Coste
- El trabajo puede esperar en la queue — el resultado no es instantáneo.
- Relaciones
- La base de Resilience y Load Leveling.
Asynchronous Processing — no esperar el resultado
Enviar una carta en lugar de mantener una conversación — la mandas y sigues con lo tuyo, confiando en que la leerán y actuarán después, sin que tú estés allí.
Esto es trabajo asíncrono: el emisor no espera el resultado. Lanza el mensaje y continúa, y el resultado ocurre después, por otra vía. Renuncias a la respuesta instantánea de una llamada directa, y a cambio dejas de estar bloqueado. Para todo lo que no necesita una respuesta inmediata, ese trato es la base de los sistemas rápidos y resilientes.
- Problema
- Esperar un resultado que no necesitas ahora mismo.
- Idea
- Enviar el mensaje y seguir; el resultado ocurre después, por otra vía.
- Ejemplo
Un informe se genera en segundo plano; el usuario lo recibe cuando está listo.
- Coste
Sin respuesta instantánea; es más difícil seguir la pista de lo que pasó.
- Relaciones
- Lo opuesto a Synchronous Call; trae Eventual Consistency.
Una queue es un búfer entre emisor y receptor. Deja un mensaje y sigue adelante — el trabajo queda desacoplado en el tiempo, hecho de forma asíncrona cuando el otro lado está listo.
Tres roles hacen funcionar una queue, y ponerles nombre aclara la mayor parte de la jerga. Un lado crea mensajes, otro los atiende, y algo en el medio los guarda con seguridad.
Producer / Consumer — un lado crea trabajo, el otro lo hace
Una cocina: los camareros cuelgan comandas y los cocineros las van descolgando una a una para prepararlas. Los dos lados nunca hablan directamente — el riel de comandas es toda la interfaz.
El lado que crea mensajes es el producer (o publisher); el lado que los procesa es el consumer (o worker). El producer deja una comanda; el consumer recoge una, hace el trabajo y pasa a la siguiente. No se conocen ni se esperan — solo conocen la queue. Esta separación limpia permite construir, escalar y cambiar cada lado por su cuenta.
- Qué es
El producer crea mensajes; el consumer los toma y hace el trabajo.
- Idea
- Los lados conocen solo la queue, no se conocen entre sí.
- Ejemplo
La app web deja «redimensiona esta foto»; un worker toma el mensaje y la redimensiona.
- Trampa
- El producer no sabe cuándo, ni quién, hará el trabajo.
- Relaciones
Un Broker se sitúa entre ellos; muchos consumers en una queue son Competing Consumers.
Message Broker — el broker guarda los mensajes con seguridad
Una oficina de correos entre remitente y destinatario: toma tu carta, la guarda y la conserva hasta que el destinatario la recoge — así no se pierde nada si no está.
En el medio está el message broker — software como RabbitMQ o Apache Kafka que recibe mensajes, los almacena de forma fiable y los entrega a los consumers. Es la oficina de correos del sistema. Su fiabilidad es el punto clave: aunque todos los consumers estén caídos, el broker guarda los mensajes hasta que alguien esté listo para procesarlos, así que el trabajo queda aparcado, no perdido.
- Problema
Los mensajes necesitan un lugar seguro donde vivir hasta que alguien los tome.
- Idea
Un software dedicado recibe, almacena y entrega mensajes — la oficina de correos del sistema.
- Ejemplo
- RabbitMQ, Apache Kafka.
- Coste
- Un sistema más que ejecutar y mantener.
- Relaciones
Guarda la Message Queue; Resilience se apoya en su fiabilidad.
Competing Consumers — añade consumers para ir más rápido
Cuando las comandas se acumulan, pones más cocineros en la línea — cada uno toma la siguiente comanda y el atraso se despeja más rápido sin cambiar cómo entran los pedidos.
Como los consumers simplemente toman el siguiente mensaje, puedes ejecutar muchos en paralelo sobre una sola queue — este es el patrón Competing Consumers. ¿Crece el atraso? Añade más workers y se reparten la carga automáticamente — cada uno agarra un mensaje distinto. Esta es una de las grandes fortalezas de una queue: escalas la parte lenta de forma independiente añadiendo consumers, sin tocar a los producers ni la queue.
- Problema
- Un solo worker no da abasto; el atraso crece.
- Idea
- Varios consumers leen una queue; cada mensaje va a uno de ellos.
- Ejemplo
Antes de una rebaja — de dos workers de redimensionado de fotos a diez.
- Coste
- El procesamiento en paralelo rompe el orden — ver Message Ordering.
- Relaciones
La base de Independent Scaling; funciona con mensajes Command.
Los producers crean mensajes, los consumers los procesan y un broker los guarda con seguridad en el medio. ¿Necesitas más rendimiento? Añade consumers — se reparten la queue automáticamente.
Un mensaje puede ser dos cosas muy distintas: una orden de hacer algo, o un anuncio de que algo ocurrió. La segunda cambia en silencio cómo diseñas sistemas enteros.
Command — un comando le dice a un worker que haga una tarea
Una orden de trabajo entregada a un departamento concreto: «redimensiona esta imagen». Nombra la tarea, espera que exactamente un equipo la haga, y ahí termina todo.
Un mensaje command es una instrucción directa dirigida a un consumer: «envía este correo», «procesa este pago». Es la queue usada como lista de tareas — el producer sabe qué debe ocurrir y entrega la tarea para que se haga una vez, por quien la tome. Este es el uso más simple de una queue: delegar trabajo concreto para hacerlo más tarde, exactamente una vez.
- Qué es
- Un mensaje-orden: «haz esto». Se nombra con un verbo.
- Cómo funciona
- El producer sabe qué debe ocurrir; un consumer hace la tarea.
- Ejemplo
SendEmail,ProcessPayment,ResizeImage.- Trampa
El producer sigue sabiendo qué trabajo hace falta — queda algo de acoplamiento.
- Relaciones
Lo opuesto a Event; a menudo lo despachan Competing Consumers.
Event — un evento anuncia que algo ocurrió
Un anuncio para toda la empresa en un tablón: «acaba de registrarse un nuevo cliente». No le dice a nadie qué hacer — quien le interese reacciona a su manera.
Un event es distinto: enuncia un hecho del pasado — «pedido realizado», «usuario registrado» — sin decir quién debe hacer qué. El producer solo lo anuncia y no sabe ni le importa quién escucha. Quizá nadie reaccione; quizá cinco servicios lo hagan. Esto invierte la relación: en lugar de ordenar a un worker concreto, difundes que algo es cierto y dejas que los interesados decidan.
- Qué es
- Un hecho del pasado: «esto ocurrió». Se nombra en pasado.
- Cómo funciona
El producer lo anuncia y no sabe quién escucha: cero, uno o cinco servicios.
- Ejemplo
OrderPlaced,UserRegistered.- Trampa
Es más difícil ver qué pasará al final — las reacciones están repartidas entre servicios.
- Relaciones
Lo opuesto a Command; se entrega vía Pub/Sub; la base de Event-driven.
Publish/Subscribe — un evento, muchas reacciones
Un periódico impreso una vez y entregado a cada suscriptor, y cada uno lo lee por sus propias razones — aficionado al deporte, inversor, fan de los crucigramas — del mismo ejemplar.
Este modelo de difusión es publish/subscribe (pub/sub): un producer publica un evento en un topic, y cada consumer interesado se suscribe y recibe su propia copia. Un solo evento «pedido realizado» puede activar a la vez el servicio de correo, el de analítica y el de envíos — esto es fan-out. El publicador ni siquiera sabe que existen. Se pueden añadir nuevas reacciones más tarde sin tocar al publicador.
- Problema
Un evento le importa a muchos servicios, y la lista no deja de crecer.
- Idea
Publicar en un topic; cada suscriptor recibe su propia copia (fan-out).
- Ejemplo
- «Pedido realizado» → correo, analítica y envíos reaccionan a la vez.
- Coste
Cada copia se procesa por separado; la cadena completa de reacciones es difícil de ver.
- Relaciones
Entrega Events; Event-driven Architecture se construye sobre él.
Event-driven Architecture — los eventos desacoplan quién conoce a quién
Añadir un suscriptor nuevo al periódico no cambia nada en cómo se escribe el periódico — el publicador nunca necesita saber quién lee.
Este es el poder profundo del diseño event-driven: el producer de un evento queda totalmente desacoplado de todos los que reaccionan a él. Para añadir una función nueva que responda a «pedido realizado», solo suscribes un consumer nuevo — sin cambiar el servicio de pedidos. Los sistemas construidos así crecen añadiendo oyentes, no editando lo que se escucha. Así evolucionan los sistemas grandes sin que todo dependa de todo.
- Problema
- Cada función nueva obliga a editar el servicio donde «ocurre todo».
- Idea
Los servicios anuncian eventos; las funciones se añaden como oyentes nuevos.
- Ejemplo
Dar puntos de fidelidad por pedido — suscribir un servicio nuevo a «pedido realizado».
- Coste
Eventual Consistency, y una petición que salta entre mensajes es más difícil de depurar.
- Relaciones
Construida sobre Event y Pub/Sub; da Independent Scaling.
Un command le dice a un consumer que haga una tarea. Un event anuncia un hecho y deja que cualquiera reaccione — y pub/sub reparte un evento a muchos, desacoplando quién conoce a quién.
Las queues añaden piezas móviles, así que tienen que ganárselo. Lo hacen comprando tres cosas difíciles de conseguir de otra forma: resiliencia, manejo suave de picos y escalado independiente.
Resilience — un consumer caído solo retrasa el trabajo
Si la cocina cierra una hora, las comandas simplemente esperan en el riel — cuando reabre, los cocineros despachan el atraso. No se pierde ningún pedido.
Como el broker guarda los mensajes, que un consumer se caiga no pierde trabajo — los mensajes esperan hasta que vuelva y entonces se procesan. Compáralo con una llamada directa, donde un servicio caído significa un fallo rotundo. La queue convierte «el servicio está caído» de un error duro en un retraso temporal. Esta resilience — el trabajo sobrevive a un fallo y se reanuda — suele ser la razón más importante por la que los equipos recurren a una queue.
- Problema
Con una llamada directa, un servicio caído significa un error para todos.
- Idea
- El broker guarda los mensajes; un fallo se convierte en un retraso.
- Ejemplo
El worker de correo se cae una hora — los correos esperan en la queue y salen tras el reinicio.
- Coste
- Mientras el consumer está caído, el trabajo se acumula y se hace tarde.
- Relaciones
Cura Failure Propagation; se apoya en la fiabilidad del Broker.
Load Leveling — absorbe los picos
Un embalse entre una crecida repentina y un pueblo: la oleada entra en el embalse, que suelta el agua a un ritmo constante y seguro río abajo.
Cuando llega de golpe una avalancha de peticiones — una rebaja, un momento viral — una queue te permite nivelar la carga: el pico llena la queue y los consumers la vacían a su propio ritmo constante. El sistema lento de más abajo nunca ve el pico, solo un flujo manejable y parejo. A la presión que genera el atraso se la llama backpressure. Sin una queue, el mismo pico golpearía directamente al sistema y probablemente lo derribaría.
- Problema
Un pico de tráfico golpea directamente a un sistema lento y lo derriba.
- Idea
- El pico llena la queue; los consumers la despachan a su propio ritmo.
- Ejemplo
Una rebaja: miles de pedidos por minuto se procesan como un flujo constante.
- Coste
El atraso crece y el trabajo se hace tarde (backpressure) — vigila la longitud de la queue.
- Relaciones
Se apoya en Temporal Decoupling; los Competing Consumers despejan el atraso.
Independent Scaling — escala y evoluciona cada lado por su cuenta
Puedes contratar más cocineros, cambiar el equipo de la cocina o añadir una estación nueva — todo sin cambiar cómo toman los pedidos los camareros, porque solo tocan el riel de comandas.
El desacoplamiento significa que cada lado puede cambiar de forma independiente (independent scaling). Sube o baja los consumers según la demanda; reescribe un consumer en otro lenguaje; añade un consumer nuevo que reaccione a eventos existentes — todo sin tocar a los producers. La queue es una costura estable entre las partes del sistema, y las costuras estables son lo que permite que un sistema grande crezca y cambie por piezas en lugar de todo a la vez.
- Problema
- Cambiar una parte obliga a tocarlas todas.
- Idea
- La queue es una costura estable; cada lado cambia por su cuenta.
- Ejemplo
Un worker se reescribe en otro lenguaje — los producers ni se enteran.
- Coste
- El formato del mensaje se vuelve un contrato — cámbialo con cuidado.
- Relaciones
Lo entregan Competing Consumers y Event-driven Architecture.
Las queues compran resiliencia (el trabajo sobrevive a una caída), load leveling (los picos se absorben) y escalado independiente — beneficios que una llamada directa simplemente no puede darte.
La mensajería asíncrona resuelve problemas reales y crea otros nuevos. Ninguno es un obstáculo insalvable, pero fingir que no existen es como los sistemas con queues acaban con errores sutiles y desesperantes.
At-least-once e Idempotency — los mensajes pueden llegar dos veces
Para estar seguro, el correo a veces entrega una copia de una carta de la que no está seguro que llegó — mejor dos veces que ninguna, pero ahora podrías actuar dos veces sobre la misma instrucción.
La mayoría de los brokers garantizan entrega at-least-once (al menos una vez): prefieren enviar un mensaje dos veces antes que arriesgarse a perderlo, así que un consumer puede recibir ocasionalmente el mismo mensaje más de una vez. Si «cobrar al cliente» se ejecuta dos veces, es un problema real. La solución es la idempotency: diseñar el trabajo para que hacerlo dos veces tenga el mismo efecto que hacerlo una (comprobar primero «¿ya está cobrado?»). Asume duplicados; hazlos inofensivos.
- Problema
Entrega at-least-once: el mismo mensaje puede llegar más de una vez.
- Idea
Hacer el trabajo de modo que ejecutarlo dos veces tenga el mismo efecto que una.
- Ejemplo
Antes de cobrar, comprobar «¿el pedido 42 ya está cobrado?» — si sí, saltar.
- Coste
- Necesitas recordar en algún sitio qué ya se ha hecho.
- Relaciones
Imprescindible para todo Consumer; junto con la Dead-Letter Queue hace seguros los reintentos.
Message Ordering — el orden no está garantizado
Dos cartas enviadas en secuencia pueden llegar en cualquier orden — así que si el paso dos aparece antes que el paso uno, el destinatario se confunde.
Con muchos mensajes y muchos consumers en paralelo, los mensajes no se procesan necesariamente en el orden en que se enviaron. Si «actualizar dirección» y «eliminar cuenta» llegan desordenados, sale un disparate. Algunos sistemas conservan el orden dentro de una categoría a cierto coste; a menudo es más barato diseñar un trabajo que no dependa de un orden estricto. Sea como sea, nunca asumas orden a menos que lo hayas dispuesto expresamente.
- Problema
Los consumers en paralelo no procesan los mensajes en el orden en que se enviaron.
- Idea
No confiar en el orden — o disponerlo explícitamente dentro de una categoría.
- Ejemplo
«Eliminar cuenta» se procesó antes que «actualizar dirección» — el resultado es un disparate.
- Coste
- El orden estricto exige esfuerzo y estorba al paralelismo.
- Relaciones
El precio de Competing Consumers; vecino de Eventual Consistency.
Eventual Consistency — el resultado es consistente con el tiempo
Un anuncio que se difunde por una oficina: durante unos momentos unos lo saben y otros no, hasta que la noticia llega a todos y vuelven a coincidir.
Como las reacciones ocurren de forma asíncrona, el sistema es eventualmente consistente: justo después de un evento, distintas partes pueden discrepar brevemente — el pedido existe pero la analítica aún no lo ha contado. Se pone al día en instantes, pero la «consistencia instantánea en todas partes» desaparece. Diseñas alrededor de esta brecha, mostrando a los usuarios estados intermedios razonables, en lugar de asumir que todas las partes se actualizan en el mismo instante.
- Problema
Justo después de un evento, partes del sistema ven brevemente cosas distintas.
- Idea
Aceptar la brecha: cada parte se pone al día y coincide — un poco después.
- Ejemplo
El pedido se crea pero aún no está en el informe; un momento después, sí.
- Coste
- Hay que diseñar estados intermedios para el usuario («procesando…»).
- Relaciones
Consecuencia de Asynchronous Processing y Event-driven Architecture.
Dead-Letter Queue — un mensaje envenenado necesita adónde ir
Una carta con la que nadie puede hacer nada — borrosa, imposible — no puede reintentarse para siempre atascando la fila. Se aparta en una bandeja especial para que alguien la revise.
Algunos mensajes nunca pueden procesarse con éxito — están mal formados o se refieren a datos que ya no existen. Si se dejan, un poison message (mensaje envenenado) así se reintenta para siempre y bloquea la queue. La respuesta estándar es una dead-letter queue: tras unos cuantos intentos fallidos, el mensaje se aparta a una queue separada para inspeccionarlo, de modo que deja de envenenar el flujo. Planifica los mensajes que fallan, o un solo mensaje malo detiene todo lo que hay detrás.
- Problema
Un poison message falla siempre, se reintenta sin fin y bloquea la queue.
- Idea
Tras unos cuantos fallos, apartar el mensaje a una queue separada para revisarlo.
- Ejemplo
- Un mensaje sobre un usuario eliminado va a la DLQ tras tres intentos.
- Coste
Alguien tiene que vigilar la DLQ, o se vuelve un cementerio de trabajo perdido.
- Relaciones
Los reintentos solo son seguros con Idempotency; mantiene el flujo en marcha para Resilience.
La mensajería asíncrona trae duplicados (se manejan con idempotency), orden no garantizado, eventual consistency y mensajes que fallan (usa una dead-letter queue). Planifica los cuatro.
Una queue es una herramienta potente, no una opción por defecto. La habilidad está en recurrir a ella cuando desacoplar de verdad compensa, y mantener la llamada directa cuando la simplicidad vale más.
Queue vs Direct Call — usa una queue cuando esperar es el problema
Tomas un número y te vas por un servicio lento que recogerás después — pero para un sí o un no rápido simplemente preguntas en el mostrador, porque sacar un ticket sería más absurdo que esperar.
Recurre a una queue cuando el trabajo es lento, con picos o no urgente, cuando quieres que el que llama siga siendo rápido, o cuando varios servicios deben reaccionar a una misma cosa. Mantén una llamada directa cuando necesitas una respuesta inmediata para continuar — una consulta de precio, una comprobación de permisos — porque ahí la simplicidad y el resultado instantáneo valen más que el desacoplamiento. Ajusta la herramienta a si esperar es de verdad el problema.
- Pregunta
- ¿El que llama necesita la respuesta para continuar?
- Queue
El trabajo es lento, con picos, no urgente o lo necesitan muchos (fan-out).
- Llamada directa
Necesitas una respuesta instantánea: una consulta de precio, una comprobación de permisos.
- Coste de la queue
Un broker, duplicados, orden, eventual consistency, trazado más difícil.
- Relaciones
- La elección entre Synchronous Call y Message Queue.
No recurras a ella por reflejo
Instalar una sala de correo completa con sistema de clasificación para pasarle una nota a la persona del escritorio de al lado — la maquinaria cuesta ya más que el problema que resuelve.
Las queues añaden complejidad real: un broker que ejecutar, duplicados y orden que manejar, eventual consistency alrededor de la cual diseñar, y más dificultad para trazar una petición que ahora salta entre mensajes. Para un sistema simple con una llamada rápida entre dos partes, esa carga no compensa. Añade una queue cuando un beneficio concreto — resiliencia, escala, desacoplamiento — justifique el coste, no porque lo event-driven suene avanzado.
Los conceptos están conectados
Una cinta transportadora: de un dolor a una cura — y la cura tiene sus propios beneficios y sus propios efectos secundarios.
Esta es la imagen completa. El dolor de la synchronous call lo cura una message queue, guardada por un broker. Por la queue viajan commands (a un consumer) y events (a muchos, vía pub/sub). Eso compra los beneficios — resiliencia, load leveling, escalado — y trae las partes difíciles: duplicados, orden, eventual consistency y la DLQ.
- ¿Es esperar el problema — el trabajo es lo bastante lento, con picos o no urgente como para desacoplarlo?
- Command o event — ¿un worker haciendo una tarea, o muchos servicios reaccionando a un hecho?
- ¿Es idempotente el trabajo — seguro de ejecutar dos veces, ya que los mensajes pueden llegar dos veces?
- ¿Asume orden, y lo he dispuesto o lo he eliminado del diseño?
- ¿Puede el sistema tolerar una breve inconsistencia eventual?
- Adónde van los mensajes fallidos — ¿hay una dead-letter queue?
- Pones en queue el trabajo lento, con picos y no urgente y mantienes las llamadas directas para respuestas instantáneas.
- Tus consumers son idempotentes, así que un mensaje duplicado no hace daño.
- No asumes orden a menos que lo hayas dispuesto explícitamente.
- Diseñas para eventual consistency en lugar de esperar un acuerdo instantáneo.
- Los mensajes fallidos acaban en una dead-letter queue en lugar de atascar la fila.
Resumen: los 21 conceptos
El problema de la llamada directa
- Synchronous Callrequest–response
Llamar y esperar. Simple, pero acopla los servicios en el tiempo.
- Failure Propagationcascading failure
Un servicio caído arrastra a todos los que lo llaman.
- Background Workbackground jobs
Trabajo que el usuario no debería esperar: correos, facturas, fotos.
La queue
- Message Queuequeue
Deja un mensaje y sigue; el receptor lo recoge por su cuenta.
- Temporal Decouplingbuffer in time
Un búfer: los lados no tienen que funcionar en el mismo momento.
- Asynchronous Processingasync
No esperar el resultado; el desenlace ocurre después.
Roles
- Producer / Consumerpublisher / worker
Uno escribe mensajes, el otro los procesa; solo conocen la queue.
- Message Brokerbroker
Software que almacena y entrega mensajes de forma fiable: RabbitMQ, Kafka.
- Competing Consumersworker pool
Muchos workers en una queue se reparten la carga.
Comandos y eventos
- Commandhaz esto
«Haz esto» — exactamente un consumer lo hace.
- Eventesto ocurrió
«Esto ocurrió» — cualquiera reacciona, o nadie.
- Publish/Subscribepub/sub, topic, fan-out
Un evento en un topic — cada suscriptor recibe su propia copia.
- Event-driven ArchitectureEDA
Las funciones se añaden como oyentes nuevos, no editando al publicador.
Beneficios
- Resiliencefault tolerance
La caída de un consumer es un retraso, no trabajo perdido.
- Queue-Based Load Levelingload leveling, backpressure
Un pico llena la queue; los consumers la vacían de forma constante.
- Independent Scalingindependent evolution
Cada lado escala y cambia por su cuenta.
Partes difíciles
- Idempotencyat-least-once
Los duplicados ocurren — hazlos inofensivos.
- Message Orderingordering guarantees
El orden no está garantizado a menos que lo dispongas.
- Eventual Consistencyconsistent in the end
Partes del sistema discrepan brevemente y luego se ponen al día.
- Dead-Letter QueueDLQ
Una queue aparte para los mensajes que fallan una y otra vez.
Elegir
- Queue vs Direct Callcómo elegir
Necesitas la respuesta para continuar — llamada directa; si no — una queue.
Las queues son deliberadas: recurre a una cuando desacoplar en el tiempo compra resiliencia, escala o fan-out — y mantén la llamada directa cuando una respuesta instantánea importa más que todo eso.