AWS Builder Center
Arquitectura orientada a eventos: por qué tus servicios no deberían conocerse entre sí

Arquitectura orientada a eventos: por qué tus servicios no deberían conocerse entre sí

Cómo evitar el efecto dominó en tu sistema: que un servicio falle sin arrastrar a los demás.

Series: Serverless Fundamentos (5 articles)

  1. …
  2. 3
    Arquitectura orientada a eventos: por qué tus servicios no deberían conocerse entre sí This article
Si alguna vez trabajaste en un proyecto donde un cambio en un servicio rompía otro que no tenía nada que ver, ya experimentaste el problema que la arquitectura orientada a eventos resuelve. Por ejemplo: actualizas la lógica de pagos y de repente el servicio de notificaciones deja de funcionar porque dependía del formato exacto de la respuesta que pagos devolvía. Nadie tocó notificaciones, pero se rompió igual. Y si todavía no te pasó, te va a pasar, porque es de las cosas más comunes cuando un sistema empieza a crecer.
Yo lo aprendí de la forma difícil. Tenía un sistema donde todo estaba conectado directamente, y cada vez que algo fallaba, el efecto dominó era inevitable. Un servicio se caía y arrastraba a tres más con él, uno tras otro.
La arquitectura orientada a eventos es la forma de evitar ese dominó.
📺 Y si prefieres el formato en video, puedes verlo acá:

Qué es un evento en arquitectura de software

Antes de hablar de arquitectura, necesitas entender qué es un evento en este contexto.
Un evento es un registro de que algo pasó. No es un comando que le dice a alguien "haz esto", es simplemente la documentación de un hecho: algo ocurrió en el sistema y quedó registrado.
Piensa en tu feed de notificaciones. "Tu amigo subió una historia", "te etiquetaron en un reel", "un jugador terminó una partida". Cada una de esas notificaciones existe porque algo pasó en algún servicio y ese hecho se registró como un evento. Nadie te está dando una orden, solo te informan que algo ocurrió, y tú decides si reaccionas o no.
Y lo importante es que un evento es inmutable: no se modifica después porque ya pasó. Puedes ignorar una notificación, pero no puedes hacer que no haya existido. El hecho quedó registrado y así se queda, igual que en la vida misma.

Quién produce y quién reacciona

En este modelo hay dos roles: el que anuncia que algo pasó (productor) y el que escucha y reacciona (consumidor). Lo clave es que el productor no sabe ni le importa quién va a reaccionar. Anuncia el hecho y sigue con su vida.
Imagina una plataforma de gaming donde un jugador termina una partida ranked y gana. Ese resultado es un evento: "partida finalizada, jugador X ganó". El servicio de partidas (el productor) lo anuncia y listo, su responsabilidad terminó ahí.
Pero detrás de ese evento hay varios servicios que necesitan reaccionar: uno que actualiza el ranking del jugador, otro que suma los puntos de temporada, otro que le envía la notificación de "subiste de rango", y quizás uno más que actualiza las estadísticas públicas de su perfil.
Ninguno de esos servicios se conoce entre sí, y ninguno necesita saber que los demás existen. Cada uno hace su trabajo cuando le llega el evento, de forma independiente.

El problema de conectar todo directamente

Cuando estás empezando a diseñar un sistema con múltiples servicios, la primera idea es la más obvia: conectar las cosas directamente. Si el servicio A necesita que el servicio B haga algo, A llama a B y ya.
Con el ejemplo anterior, el servicio de partidas termina un match y llama directamente al servicio de ranking. Limpio y simple cuando son pocos.
Pero el problema aparece cuando las cosas que necesitan pasar después empiezan a crecer. Ahora también necesitas sumar puntos de temporada (otra llamada directa), enviar una notificación (otra más), actualizar estadísticas (otra más). De repente el servicio de partidas, cuyo único trabajo es manejar matches, tiene código para hablar con cuatro servicios diferentes y manejar los errores de cada uno.
Y lo verdaderamente problemático es el escenario de fallo. Si el servicio de notificaciones se cae, el servicio de partidas recibe un error. ¿Qué debería hacer? No tiene sentido marcar la partida como fallida porque la partida sí se jugó. ¿Ignora el error? ¿Reintenta indefinidamente? Cualquier decisión es mala porque está lidiando con un problema que no es suyo.
Eso es acoplamiento: cuando las piezas de tu sistema dependen directamente unas de otras, y un fallo en cualquiera de ellas puede propagarse y afectar a las demás.
Punto a punto: el fallo en notificaciones se propaga de vuelta al servicio de partidas

Pub/Sub: publicar sin saber quién escucha

La alternativa es usar un intermediario. En vez de que el productor llame directamente a cada consumidor, publica su evento en un canal (también llamado "topic"), y los consumidores que estén interesados se suscriben a ese canal para recibir los eventos automáticamente.
Es como la diferencia entre mandar un DM a 15 personas individualmente versus publicar algo en un grupo donde ya están todos. Tú publicas una vez, y cada quien en el grupo lo lee y reacciona como necesite.
Ese patrón se llama pub/sub (publicar/suscribir):
  • El productor publica el evento en un canal y se desentiende
  • Cada consumidor suscrito recibe una copia del evento
  • Si mañana necesitas que un servicio nuevo reaccione a ese evento, solo lo suscribes al canal sin tocar ni al productor ni a los consumidores existentes
  • Si un consumidor se cae, los demás ni se enteran porque cada uno opera por su cuenta
Eso es desacoplamiento: las piezas de tu sistema se comunican a través de eventos sin depender directamente unas de otras, sin conocerse, sin afectarse mutuamente.
Pub/Sub: el productor publica en un canal

El efecto dominó en acción

Veamos qué pasa cuando las cosas salen mal en cada modelo con un ejemplo diferente.
Piensa en una app de streaming de música donde un artista sube un álbum nuevo. Cuando eso ocurre, el sistema necesita hacer varias cosas: notificar a los fans que siguen al artista, indexar las canciones en el buscador, evaluar si el álbum entra en alguna playlist editorial, y generar las previsualizaciones de audio para compartir en redes.

Si todo está conectado directamente

El servicio de uploads llama a cada uno de esos servicios en secuencia. Pero el servicio de previsualizaciones está saturado y empieza a responder lento. Como el servicio de uploads está esperando su respuesta, se acumulan las requests. Los artistas empiezan a ver timeouts cuando intentan subir música. Y el problema es que el upload sí se completó, la música sí se guardó, pero el servicio de uploads se quedó trabado esperando una respuesta de un servicio secundario.
Un problema en las previsualizaciones terminó afectando la capacidad de subir música. Las fichas de dominó cayendo.

Si usas pub/sub

El servicio de uploads guarda la música, publica el evento "álbum publicado" en un canal, y le dice al artista "listo, tu álbum se subió correctamente". El servicio de previsualizaciones está saturado, pero eso no afecta a nadie más: los eventos se acumulan en su cola y los procesa cuando se desahogue. Mientras tanto, las notificaciones a fans ya salieron, el buscador ya indexó las canciones, y la playlist editorial ya lo evaluó.
Cada pieza del sistema avanza a su propio ritmo sin depender de la velocidad o la salud de las demás.

Cómo se manejan los fallos sin tu intervención

Una duda que siempre aparece es: "si desacoplé todo, ¿cómo me aseguro de que nada se pierda?". Y la respuesta es que los sistemas de mensajería (donde viven esos canales) ya tienen mecanismos para eso:
Persistencia: el evento queda almacenado hasta que un consumidor confirme que lo procesó correctamente. No es como un story de Instagram que desaparece en 24 horas, aquí el mensaje se queda el tiempo que haga falta. En AWS, Amazon SQS  hace exactamente esto con sus colas de mensajes.
Reintentos automáticos: si un consumidor recibe un evento y falla al procesarlo (porque su base de datos no respondió, o porque hubo un error temporal), el sistema le vuelve a entregar el evento después de un rato para darle otra oportunidad, sin que tú tengas que escribir esa lógica. SQS maneja esto con un mecanismo llamado visibility timeout: si no confirmas que procesaste el mensaje, vuelve a aparecer en la cola.
Buzón de problemas: si un evento falla repetidamente (por ejemplo, 3 veces seguidas), se mueve automáticamente a un lugar separado para revisión manual, de forma que no bloquea a los miles de eventos que sí pueden procesarse bien. En AWS esto se llama Dead Letter Queue (DLQ), y es una cola de SQS donde van a parar los mensajes problemáticos.
Esa lógica de reintentos, persistencia y aislamiento de errores no la tienes que programar tú. Tu servicio solo se preocupa por su propia lógica de negocio.

Cuándo la comunicación directa sigue siendo la respuesta correcta

No todo se resuelve con pub/sub, y es importante saber cuándo una llamada directa es lo que necesitas.
Si un servicio necesita una respuesta inmediata de otro para poder continuar, pub/sub no te sirve porque es asíncrono por naturaleza. Por ejemplo, si un jugador quiere comprar una skin con monedas del juego, necesitas verificar su saldo antes de completar la compra. Esa verificación tiene que ser directa e inmediata, no puedes publicar un evento y esperar a que alguien te responda eventualmente.
La regla general es simple:
SituaciónUsa punto a puntoUsa pub/sub
Necesitas una respuesta para continuar✅❌
Múltiples servicios reaccionan al mismo hecho❌✅
Un fallo secundario no debe afectar la operación principal❌✅
Solo hay dos servicios involucrados y la operación es síncrona✅❌
El sistema va a crecer y van a aparecer más consumidores❌✅
La pregunta correcta nunca es "¿cuál es mejor?" sino "¿qué necesita este flujo específico?". Y en muchos sistemas reales, terminas usando ambos patrones: llamadas directas para lo que necesita respuesta inmediata, y pub/sub para lo que puede pasar en paralelo después.

El cambio mental que hace click

Lo más valioso de entender la arquitectura orientada a eventos no es un servicio específico ni una herramienta, es un cambio en la forma de pensar.
Cuando diseñas con llamadas directas, piensas en secuencias. Tu mente arma un flujo secuencial: "primero pasa esto, después esto otro, luego esto". Y si un paso se rompe, todo el flujo se detiene.
Cuando diseñas con eventos, piensas en reacciones. Te preguntas "cuando este hecho ocurra, ¿quién necesita saberlo?" y defines qué debe pasar ante cada evento, sin preocuparte por el orden exacto ni por coordinar a todos los consumidores. Cada pieza sabe su trabajo y lo hace cuando le toca.
En AWS, estos patrones tienen servicios concretos: el canal donde publicas eventos es Amazon SNS , la cola donde los eventos esperan su turno es Amazon SQS, y la puerta de entrada que recibe peticiones de tus usuarios es Amazon API Gateway . Cómo funcionan en detalle es tema del próximo artículo.
¿Te resultó útil este artículo? Si conoces a alguien que está diseñando su primer sistema con múltiples servicios y no sabe cómo conectarlos sin que todo se rompa en cadena, compártele esto. Y si ya tuviste ese momento donde entendiste que tus servicios no tienen que conocerse entre sí, me encantaría escuchar cómo llegaste ahí.
Si quieres ver estos conceptos de serverless en acción, pásate por el canal de AWS Developers en Español  donde publicamos videos sobre arquitecturas event-driven, Lambda y más.

Series: Serverless Fundamentos (5 articles)

  1. …
  2. 3
    Arquitectura orientada a eventos: por qué tus servicios no deberían conocerse entre sí This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article