¿Cómo manejas el procesamiento de eventos en fan-out a escala — un evento que dispara muchos consumidores downstream?
Un solo evento de negocio puede tener diez consecuencias independientes — hacer bien el fan-out significa agregar la undécima sin tocar al productor ni a ningún consumidor hermano.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cómo manejas el procesamiento de eventos en fan-out a escala — un evento que dispara muchos consumidores downstream?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#La forma del problema
Un solo evento de negocio rara vez tiene una sola consecuencia. Cuando se dispara un evento "OrderPlaced" (pedido creado), un sistema de pagos quiere reservar inventario, un sistema de notificaciones quiere enviar un correo de confirmación, un sistema de fraude quiere calificar el pedido casi en tiempo real, una plataforma de datos quiere aterrizarlo en el warehouse, y una integración con un partner podría necesitar disparar un webhook. Son de cinco a diez reacciones downstream independientes ante un solo hecho upstream — y ese número solo crece a medida que crece el negocio. La pregunta de entrevista "¿cómo manejas el fan-out a escala?" en realidad pregunta: ¿cómo sigues agregando consumidores sin que ninguno quede acoplado a los demás, ni al productor?
#El error central: una sola cola compartida
#Principio 1: desacoplar al productor del número de consumidores
El servicio de pedidos que publica OrderPlaced nunca debería saber ni preocuparse por cuántas cosas reaccionan a ese evento. Publica una sola vez, a un topic/bus. Agregar un sexto consumidor el próximo trimestre debería requerir cero cambios en el productor — ese es exactamente el punto de una arquitectura orientada a eventos frente a llamadas directas entre servicios. En concreto: un topic de Kafka al que se pueda unir cualquier número de consumer groups, o un topic de SNS que haga fan-out a cualquier número de colas SQS suscritas, o un bus de EventBridge con reglas independientes que enrutan a targets independientes.
#Principio 2: aislar los dominios de falla
Cada consumidor necesita su propio mecanismo de entrega — su propio consumer group de Kafka con sus propios offsets, o su propia cola de SQS suscrita al topic de fan-out— específicamente para que la caída de un consumidor no pueda bloquear a otro. Si el endpoint del webhook del partner está caído durante una hora, eso debería estancar únicamente la cola del consumidor de webhooks (que sigue acumulando y reintentando), no a los consumidores de inventario o correo, que no tienen nada que ver con eso. Este es el error de fan-out más común: los equipos comparten una cola o un consumer group entre asuntos no relacionados para ahorrar infraestructura, y luego una integración downstream lenta o rota tumba todo el pipeline con ella.
#Principio 3: aislar throughput y escalado
Distintos consumidores tienen perfiles de carga y latencia radicalmente distintos. La calificación de fraude puede necesitar reacción en menos de un segundo y escalar con el volumen de solicitudes; el cargador de analítica puede hacer batch cada cinco minutos sin importar el volumen; el envío de correos está limitado por la tasa del proveedor de email, no por tu infraestructura. Como cada consumidor es dueño de su propia cola/consumer group, cada uno puede escalar su propio pool de workers de forma independiente — el consumer group de fraude puede correr veinte instancias en paralelo mientras el de correo corre dos, sin ninguna coordinación entre ambos.
#Principio 4: retry y dead-lettering por consumidor
La entrega al menos una vez combinada con N consumidores independientes significa que cada uno necesita su propia política de reintentos y su propia dead-letter queue. Un evento malformado que rompe el deserializador del consumidor de puntos de lealtad debería ir a la dead-letter solo en la cola de ese consumidor después de N reintentos — no debe bloquear los mensajes posteriores de esa cola, y desde luego no debe afectar al consumidor de inventario, que puede procesar ese mismo evento exitosamente. Trata la DLQ de cada consumidor como su propia superficie de alertas, propiedad del equipo dueño de ese consumidor.
#Principio 5: el orden es por consumidor, no global
No intentes garantizar un orden global único entre todos los consumidores de un evento distribuido en fan-out — eso rara vez es alcanzable y rara vez se necesita. Lo que sí puedes y a menudo debes garantizar es el orden dentro de un consumidor, para una clave dada: el consumidor de inventario necesita que OrderPlaced se procese antes que OrderCancelled para el mismo ID de pedido, lo cual logras particionando el stream de ese consumidor por ID de pedido (clave de partición de Kafka, o un message group ID de SQS FIFO acotado a la cola de ese consumidor) — independientemente de cómo esté ordenado o particionado cualquier otro consumidor.
#Principio 6: idempotencia, siempre
El fan-out combinado con reintentos y rebalanceo de consumer groups garantiza entrega al menos una vez, no exactamente una vez, a cada consumidor. Todo consumidor debe ser idempotente ante la reentrega del mismo evento — típicamente rastreando los IDs de eventos ya procesados (o una clave de idempotencia natural) antes de aplicar un efecto, no confiando en que la infraestructura deduplique por ti.
Cada rama debajo del bus es independiente: un consumidor estancado o saturado únicamente acumula su propia cola/offsets, limita sus propios workers y llena su propia DLQ. Nada de esa falla es visible para, ni capaz de bloquear, ninguna rama hermana.
🧠 Check your understanding
0/3 · 0/3 answered1. Un equipo hace fan-out de eventos OrderPlaced haciendo que cinco servicios distintos lean de una sola cola de SQS compartida, y cada servicio debe ignorar los mensajes que no le interesan. ¿Cuál es el problema principal de este diseño?
2. En un diseño de fan-out bien aislado, ¿qué debería pasarle al procesamiento del consumidor de Notificaciones si el servicio downstream del consumidor de Calificación de Fraude se cae durante dos horas?
3. ¿Por qué es necesaria la idempotencia por consumidor incluso cuando el sistema de mensajería garantiza correctamente la entrega al menos una vez?