AWS 7 jul 2026 · 8 min de lectura

EventBridge: desacoplar servicios sin montar un monstruo de colas

Yohangel Ramos

Yohangel Ramos

Tech Lead · Senior Fullstack Developer

Durante mucho tiempo mi forma por defecto de conectar dos servicios fue la más obvia: el servicio A llama al servicio B. Un POST, una Lambda invocando a otra, una escritura que dispara un webhook. Funciona hasta que tienes cinco consumidores del mismo evento y cada nuevo consumidor te obliga a tocar el productor. Ahí es donde EventBridge cambió mi arquitectura: el productor deja de saber quién lo escucha. Emite "pasó esto" a un bus y se olvida. Los consumidores se suscriben por su cuenta con reglas de patrón. Elegí este modelo en varios servicios de AWS porque el acoplamiento entre equipos me estaba costando más que la latencia extra; a cambio, acepté que depurar un sistema event-driven es más difícil que seguir una llamada síncrona. Este artículo es cuándo vale la pena y cuándo no.

El problema que resuelve: el productor no debería conocer a sus consumidores

Imagina un evento de dominio simple: PedidoConfirmado. Cuando se confirma un pedido, hay que facturar, notificar al cliente, reservar inventario y actualizar analítica. La versión ingenua es que el servicio de pedidos llame a los cuatro. El día que marketing quiere enterarse también, alguien tiene que abrir el código de pedidos, añadir la quinta llamada, testearla y desplegarla. El productor acumula responsabilidades que no son suyas.

Con un bus de eventos, el servicio de pedidos emite un único evento y termina. Cada consumidor decide si le interesa. Añadir marketing es crear una regla nueva que apunta a su target, sin tocar pedidos. El acoplamiento pasa de "código a código" a "esquema de evento a esquema de evento", que es mucho más barato de mantener.

El patrón de reglas: filtrar en el bus, no en el consumidor

Lo que más me gustó de EventBridge frente a un SNS clásico es que el filtrado vive en la regla, declarativo, sobre el contenido del evento. No entrego el evento a una Lambda para que ella decida si le importa: el bus solo entrega lo que hace match.

{
  "source": ["pedidos.service"],
  "detail-type": ["PedidoConfirmado"],
  "detail": {
    "total": [{ "numeric": [">", 500] }],
    "pais": ["ES", "MX", "CO"]
  }
}

Esa regla solo dispara para pedidos confirmados de más de 500 en tres países. El consumidor no ejecuta ni una vez para el resto. Antes ese if vivía dentro de la función, invocada millones de veces para descartar la mayoría; ahora el descarte es gratis y no aparece en mi factura de Lambda ni en mis logs.

Dónde EventBridge NO es la respuesta

Ser honesto con los trade-offs es lo que separa una decisión de arquitectura de un acto de fe. EventBridge no es gratis en complejidad.

Si necesitas la respuesta del consumidor, no uses un bus. Es fire-and-forget: emites y no sabes qué pasó después salvo que montes otro evento de vuelta. Para un flujo request/response —el usuario espera un resultado en pantalla— una llamada síncrona directa sigue siendo lo correcto. Meter un event bus ahí solo añade latencia y una máquina de estados que nadie pidió.

Tampoco lo uso cuando el orden estricto es un requisito duro. EventBridge no garantiza orden, y puede entregar el mismo evento más de una vez. Si tu caso necesita procesar cosas en secuencia exacta, una cola FIFO de SQS encaja mejor. De hecho, un patrón que me funciona es EventBridge para el fan-out y SQS como buffer delante de cada consumidor lento, combinando lo mejor de ambos.

💡 La pregunta que decide todo: ¿el productor necesita saber qué le pasó al consumidor? Si la respuesta es sí, no tienes un evento, tienes una llamada. No lo disfraces de event-driven.

La entrega "al menos una vez" te obliga a ser idempotente

Este es el detalle que la gente descubre en producción y no en el diseño. EventBridge garantiza entrega at-least-once, lo que significa que tu consumidor puede recibir PedidoConfirmado dos veces por el mismo pedido. Si facturas en cada recepción, acabas de cobrar dos veces.

La solución no es rezar para que no pase: es diseñar el consumidor para que procesar el mismo evento dos veces dé el mismo resultado que procesarlo una. Una clave de idempotencia por evento, una tabla que registra "ya procesé este ID", y un INSERT ... ON CONFLICT DO NOTHING en Postgres antes de hacer el trabajo con efectos.

async function handle(event: PedidoConfirmado) {
  const inserted = await db.processedEvents.createIfAbsent(event.id);
  if (!inserted) return; // ya lo procesamos, salimos limpio
  await facturar(event);
}

No es código elegante, es código que sobrevive a la realidad. Cualquier arquitectura event-driven que no trate la idempotencia como requisito de primera clase está construyendo sobre arena.

Observabilidad: el precio real que pagué

Lo más caro de adoptar EventBridge no fue el servicio, fue la observabilidad. En una llamada síncrona sigues el stack trace y ves todo el camino. En un bus, el productor emitió y se fue; el consumidor falló tres saltos después; y correlacionar ambos requiere que hayas propagado un correlationId en el detail de cada evento desde el día uno.

Lo aprendí tarde y lo pagué en incidentes que costaron horas de más solo por no poder unir la causa con el efecto. Ahora todo evento lleva su ID de correlación, todos los consumidores lo loguean, y una DLQ por regla captura lo que falla para que ningún evento se pierda en silencio. Con eso, el desacoplamiento sale a cuenta. Sin eso, cambias un problema de acoplamiento por uno de depuración a ciegas, y no está claro que ganes.

Yohangel Ramos

Escrito por Yohangel Ramos

Senior Fullstack Developer y Tech Lead. Construyo con React, Next.js, Nest.js y AWS — y escribo sobre lo que aprendo en el camino.

Hablemos →

Sigue leyendo

IA

Embeddings más baratos: recortar dimensiones y cuantizar sin perder recall

IA

Qué va a pasar con el desarrollo de software: predicciones con fechas (julio 2026)