StackPractices
intermediate Por Mathias Paulenko

Arquitecturas Event-Driven con Lambda y EventBridge

Cómo diseñar sistemas débilmente acoplados usando funciones serverless disparadas por eventos de colas de mensajes, bases de datos y webhooks.

Visión general

La arquitectura orientada a eventos elimina las llamadas HTTP directas entre servicios: en lugar de llamarse unos a otros, los servicios hablan mediante eventos. Cuando un usuario sube una imagen, sale un evento ImageUploaded. Un generador de miniaturas lo escucha y crea la versión redimensionada; un extractor de metadatos lo escucha también y actualiza el índice de búsqueda. Ningún servicio sabe que el otro existe — solo conoce el evento.

Las funciones serverless encajan bien en este modelo: cuestan cero en reposo y se levantan solas cuando llega una ráfaga de eventos. AWS Lambda, SQS, EventBridge y SNS forman la columna vertebral de la mayoría de plataformas serverless event-driven.

Cuándo usarlo

Usa esta receta cuando:

  • Procesas cargas asíncronas que no necesitan respuesta inmediata (procesamiento de imágenes, generación de informes, envío de emails)
  • Quieres desacoplar servicios para desplegarlos, escalarlos y fallarlos de forma independiente
  • Un mismo evento debe llegar a varios consumidores — cada uno reaccionando de forma distinta al mismo hecho
  • El sistema debe absorber picos de tráfico sin aprovisionar capacidad por adelantado
  • Hay que reaccionar a cambios en los datos (CDC de base de datos) o en sistemas externos (webhooks, subidas de archivos)

No uses event-driven cuando quien llama necesita el resultado de forma síncrona, cuando solo hay un consumidor para siempre, o cuando el orden estricto de extremo a extremo es un requisito duro — una cola simple o una llamada directa serán más sencillas.

Solución

Lambda disparada por SQS (Python)

import json
import boto3

def lambda_handler(event, context):
    for record in event['Records']:
        body = json.loads(record['body'])
        order_id = body['orderId']

        # Procesa el pedido de forma asíncrona
        process_order(order_id)

        # El mensaje SQS se elimina automáticamente al completar con éxito
    return {'statusCode': 200}

def process_order(order_id):
    # Lógica de negocio: validar, cobrar, notificar
    print(f"Procesando pedido {order_id}")

Regla de EventBridge (Infraestructura como Código)

# SAM / CloudFormation
OrderPlacedRule:
  Type: AWS::Events::Rule
  Properties:
    EventBusName: default
    EventPattern:
      source:
        - order-service
      detail-type:
        - OrderPlaced
    Targets:
      - Arn: !GetAtt PaymentFunction.Arn
        Id: payment-target
      - Arn: !GetAtt NotificationFunction.Arn
        Id: notification-target

Publicando Eventos (Node.js)

const { EventBridgeClient, PutEventsCommand } = require('@aws-sdk/client-eventbridge');
const eb = new EventBridgeClient({ region: 'us-east-1' });

async function publishOrderPlaced(order) {
  await eb.send(new PutEventsCommand({
    Entries: [{
      Source: 'order-service',
      DetailType: 'OrderPlaced',
      Detail: JSON.stringify({
        orderId: order.id,
        amount: order.total,
        customerEmail: order.email,
      }),
    }],
  }));
}

Explicación

  • Eventos: registros inmutables de algo que ocurrió (OrderPlaced, ImageUploaded, PaymentReceived). Los eventos llevan estado pero no dictan qué deben hacer los consumidores.
  • Productores de eventos: servicios que emiten eventos cuando ocurre algo relevante. Un productor no sabe ni le importa cuántos consumidores escuchan.
  • Consumidores de eventos: funciones o servicios suscritos a tipos de evento concretos. Distintos consumidores pueden reaccionar al mismo evento a su manera.
  • Buses de eventos (EventBridge): el enrutador central de una arquitectura orientada a eventos. Cada evento se compara con tus reglas y se empuja a todos los targets que coincidan — productores y consumidores quedan desacoplados.

La regla de EventBridge de arriba es el punto de fan-out: un evento OrderPlaced se enruta a la vez a la función de pagos y a la de notificaciones, sin acoplamiento de código entre ellas:

Un servicio de pedidos publica un evento OrderPlaced en EventBridge, que lo distribuye a tres consumidores independientes: una Lambda de pagos, una Lambda de notificaciones y una cola SQS de analítica

Variantes

PatrónAcoplamientoDurabilidadIdeal para
Invocación directaFuerteNingunaFlujos simples y síncronos
Colas SQSDébilAltaProcesamiento async fiable, reintentos
EventBridgeDébilAltaEnrutado multi-consumidor, filtrado
Topics SNSDébilMediaBroadcast, notificaciones fan-out
Streams KinesisDébilAltaAnalítica en tiempo real, procesamiento ordenado

Para el ajuste fino de SQS — ventanas de batch, respuestas de batch parcial y cableado de dead-letter queue — consulta Lambda Event-Driven con Triggers SQS.

Fuera de AWS, la misma topología se traduce a los equivalentes de cada proveedor:

RolAWSAzureGCP
FunciónLambdaAzure FunctionsCloud Functions
Bus de eventosEventBridgeEvent GridEventarc
ColaSQSStorage Queues / Service BusPub/Sub
Topic fan-outSNSTopics de Event GridTopics de Pub/Sub

El modelo de acoplamiento — eventos, productores, consumidores, dead letters — es idéntico; solo cambian los nombres de servicio y las llamadas del SDK.

Lo que funciona

  • Diseña eventos en torno a hechos de negocio: OrderPlaced es mejor que ProcessOrder — describe qué ocurrió, no qué hacer, así que los consumidores siguen libres de reaccionar de forma distinta.
  • Haz los eventos inmutables y autocontenidos: incluye suficiente contexto (ID de pedido, email del cliente, importe) para que el consumidor no tenga que llamar de vuelta al productor.
  • Planifica para duplicados: la mayoría de colas entregan at-least-once, así que el mismo evento puede llegar dos veces. Los consumidores deben ser idempotentes o desduplicar usando los IDs de evento.
  • Configura dead letter queues: tras el número de reintentos configurado, los mensajes fallidos van a una DLQ para inspección en lugar de reintentar para siempre.
  • Monitoriza latencia y edad de eventos: los mensajes viejos señalan un cuello de botella de procesamiento. Alarma sobre ApproximateAgeOfOldestMessage en SQS.
  • Funciones de propósito único: cada función hace una cosa bien — la orquestación vive en las reglas del bus o en Step Functions, no dentro del handler.

Errores comunes

  • Tratar los eventos como comandos: ProcessPayment espera una acción; PaymentRequested describe un hecho. Los comandos crean acoplamiento fuerte — los eventos promueven el débil.
  • Omitir el versionado del esquema: cuando cambia el esquema de un evento, los consumidores no actualizados fallan. Versiona los eventos (OrderPlaced-v2) o usa un schema registry.
  • No manejar fallos parciales de batch: con batch sizes de SQS por encima de 1, un mensaje malo puede tumbar todo el batch a menos que devuelvas fallos por ítem (batchItemFailures).
  • Ignorar el orden de los mensajes: las colas estándar de SQS no garantizan orden — usa FIFO o números de secuencia solo cuando el orden sea un requisito real.
  • Guardar estado compartido en la función: las instancias son efímeras; el estado va en DynamoDB, S3 o en el propio evento.

Solución de problemas

  • Los mensajes reintentan sin éxito una y otra vez: hay un poison message atascado en el bucle de reintentos — verifica que la DLQ esté conectada (redrivePolicy en la cola) e inspecciona el payload fallido buscando un desajuste de esquema.
  • Un registro malo mata todo el batch: devuelve batchItemFailures con los messageId fallidos desde el handler para que solo esos reintenten — si no, Lambda reproduce todo el lote.
  • El evento llega pero ningún consumidor salta: el patrón de la regla de EventBridge no hace match — pruébalo en la consola contra los valores exactos de source/detail-type; DetailType distingue mayúsculas.
  • Los consumidores ven eventos fuera de orden: ni SQS estándar ni EventBridge preservan el orden — incluye un número de secuencia o timestamp en el payload y reordena en el consumidor si hace falta.
  • Efectos duplicados (doble cobro, doble email): entrega at-least-once — haz el consumidor idempotente guardando los event.id procesados antes de ejecutar el efecto.

Ver también

Preguntas frecuentes

¿En qué se diferencia event-driven de request-response?

Request-response (HTTP REST) es síncrono: quien llama espera un resultado. Event-driven es asíncrono: el productor dispara un evento y sigue mientras los consumidores procesan cuando pueden.

¿Puedo usar arquitectura event-driven con proveedores que no sean AWS?

Sí. Azure Functions con Event Grid, Google Cloud Functions con Pub/Sub y Apache Kafka en cualquier nube soportan patrones event-driven — el modelo de acoplamiento es el mismo, solo cambian los nombres de los servicios.

¿Cómo trazo una petición a través de varias funciones event-driven?

Genera un correlation ID en el punto de entrada y propágalo por los atributos de cada evento — X-Ray u OpenTelemetry reconstruyen la cadena completa.

¿Cuál es el tamaño máximo de un evento?

Los mensajes SQS están limitados a 256 KB, y los eventos de EventBridge también a 256 KB. Para payloads mayores, guarda los datos en S3 y envía solo la referencia — el patrón claim-check.

¿Importa el orden de los eventos en funciones serverless?

Solo a veces. La mayor parte del trabajo event-driven es insensible al orden por diseño; cuando el orden importa (inventario, contabilidad), usa SQS FIFO con un message group ID, o lleva un campo de secuencia y deja que los consumidores apliquen el último-gana.

¿Qué pasa si un consumidor está caído cuando llega el evento?

No se pierde nada: EventBridge reintenta la entrega (hasta 185 veces en 24 horas por defecto) y SQS retiene los mensajes hasta que expira el visibility timeout. Configura la DLQ de todos modos para que los reintentos agotados aterricen en algún sitio inspeccionable.