Skip to content

📓 Clase 6 — Arquitectura orientada a eventos

Curso AWS (emulador Floci) · 2026-08-09 · Carpeta: 02-Ejercicios/clase-06-eventos ⬅️ Volver al índice de clases

🎯 Qué aprendí

  • Qué significa que los servicios no se llamen entre sí y por qué eso cambia todo.
  • Las tres formas de conectar: notificación directa, cola, y publicar/suscribir.
  • SQS para desacoplar: qué pasa cuando el consumidor está caído.
  • SNS para avisar a varios a la vez sin que el emisor los conozca.
  • EventBridge como bus central con filtrado por contenido.
  • Robustez: reintentos, colas de mensajes muertos y qué hacer con lo que falla siempre.

📖 PARTE TEÓRICA

🔀 1. Nadie llama a nadie

En el backend de CENATE, cuando pasa algo, alguien llama a alguien: un servicio invoca a otro, y si el segundo está caído, el primero falla también.

En una arquitectura de eventos, los servicios anuncian que algo pasó y se desentienden:

   ACOPLADO (llamada directa)          POR EVENTOS
   ──────────────────────────          ───────────
   ServicioA ──llama──▶ ServicioB      ServicioA ──publica──▶ [ EVENTO ]
        │                                                          │
   si B esta caido,                                    ┌───────────┼───────────┐
   A falla tambien                                     ▼           ▼           ▼
                                                  ServicioB   ServicioC   ServicioD
   ✗ A debe conocer a B
   ✗ A espera a B                     ✓ A no sabe quien escucha
   ✗ agregar C = tocar A              ✓ si B esta caido, el evento espera
                                      ✓ agregar D no toca A

💡 La prueba de fuego: ¿puedes añadir un consumidor nuevo sin tocar el emisor? Si sí, está bien desacoplado. Si hay que modificar quien emite, sigues acoplado.

📬 2. Las tres formas de conectar

Cómo funcionaCuándo usarlo
Notificación (S3 → Lambda)El servicio avisa directamente a un destinoUna fuente, un destino, reacción inmediata
Cola (SQS)El mensaje espera hasta que alguien lo recogeEl consumidor puede tardar, fallar o no estar
Publicar/suscribir (SNS)Un mensaje llega a todos los suscritosVarios interesados en lo mismo
Bus (EventBridge)Reglas que filtran por contenido y enrutanMuchos tipos de evento, muchos destinos

📮 3. La cola: el amortiguador

Una cola convierte un problema de disponibilidad en un problema de tiempo:

  productor ──▶ [ m1 m2 m3 m4 ] ──▶ consumidor
                    la cola             │
                                  si esta caido,
                                  los mensajes ESPERAN
                                  (hasta 14 dias)

Dos mecanismos hacen que funcione sin coordinación:

  • Tiempo de invisibilidad: al recoger un mensaje, desaparece para los demás durante N segundos (30 por defecto). Si el consumidor lo procesa y lo borra, se acabó. Si muere antes, el mensaje reaparece y otro lo intenta.
  • Sondeo largo: en vez de preguntar mil veces por segundo, el consumidor espera hasta N segundos a que llegue algo. Menos llamadas, menos coste.

⚠️ Recoger no es borrar. Si no llamas a delete-message, el mensaje vuelve a la cola al expirar la invisibilidad. Es un fallo clásico: la función procesa lo mismo una y otra vez.

📢 4. Publicar/suscribir: uno a muchos

SQS entrega cada mensaje a un consumidor. SNS lo entrega a todos los suscritos:

                       ┌──▶ cola de facturacion
   publicar ──▶ TEMA ──┼──▶ cola de notificaciones
                       └──▶ funcion de auditoria

El emisor no sabe cuántos hay ni quiénes son. Añadir un cuarto suscriptor no toca su código.

💡 El patrón más habitual es SNS delante de varias SQS: el tema reparte, y cada cola amortigua a su consumidor. Se llama fan-out.

🚌 5. El bus: enrutar por contenido

EventBridge va un paso más allá: las reglas miran dentro del evento y deciden a dónde va.

json
{
  "source": "cenate.citas",
  "detail-type": "CitaCreada",
  "detail": { "dni": "12345601", "especialidad": "Cardiologia" }
}

Una regla con el patrón {"source": ["cenate.citas"]} captura ese evento; otra con {"detail": {"especialidad": ["Cardiologia"]}} captura solo las de esa especialidad. El emisor publica una vez y el bus reparte según reglas que se cambian sin tocarlo.

🛡️ 6. Qué pasa cuando algo falla siempre

Un mensaje que hace fallar al consumidor volverá una y otra vez, bloqueando la cola. La solución es la cola de mensajes muertos:

   cola principal ──▶ consumidor  ✗ falla
        │  reaparece                  ✗ falla
        │  reaparece                  ✗ falla   ← intento 3

   COLA DE MENSAJES MUERTOS  ← se aparta para revisarlo a mano

Se configura con RedrivePolicy y un maxReceiveCount. Sin ella, un solo mensaje defectuoso puede parar todo el procesamiento.


💻 PARTE PRÁCTICA

bash
floci start
eval $(floci env)

La cadena que ya montaste en el laboratorio, ahora entendiéndola por dentro:

   aws s3 cp informe.txt s3://documentos/


      ┌────────────┐  evento s3:ObjectCreated:*
      │     S3     │ ──────────────┐
      └────────────┘               ▼
                            ┌─────────────┐
                            │   LAMBDA    │
                            └──────┬──────┘
                     ┌─────────────┴─────────────┐
                     ▼                           ▼
              ┌────────────┐             ┌────────────┐
              │  DYNAMODB  │             │    SQS     │
              └────────────┘             └────────────┘
zsh · eventos
$ for i in 1 2 3; do aws sqs send-message --queue-url $Q --message-body "cita-$i"; done
$ sleep 15 && aws sqs get-queue-attributes --queue-url $Q \
    --attribute-names ApproximateNumberOfMessages --query 'Attributes.*' --output text
0
[esm] recibido: cita-1
[esm] recibido: cita-2
[esm] recibido: cita-3

Nadie invocó la función: la vació el disparador que conecta la cola con ella.


🏋️ EJERCICIOS CON SOLUCIÓN

🟢 Nivel 1 — El evento más simple: S3 dispara una función (1-8)

Ejercicio 1 — Crear la función que reacciona

Crea una función que registre en sus logs el nombre del archivo que la despertó.

💡 ¿Sabías que…? — el evento de S3 trae la ruta

Llega en event["Records"][0]["s3"]["object"]["key"]. La clave viene codificada como URL: los espacios aparecen como + y hay que decodificarlos.

python
# ejemplo de referencia
import urllib.parse
clave = urllib.parse.unquote_plus(record["s3"]["object"]["key"])
Ver solución
python
import json, urllib.parse
def lambda_handler(event, context):
    for r in event.get("Records", []):
        clave = urllib.parse.unquote_plus(r["s3"]["object"]["key"])
        print(f"[lab] llego: {clave}")
    return {"n": len(event.get("Records", []))}

Ejercicio 2 — Crear el bucket

Crea ej02-documentos.

💡 ¿Sabías que…? — el bucket debe existir antes del disparador

La configuración de notificaciones se guarda en el bucket. No se puede configurar sobre algo que no existe.

bash
# ejemplo de referencia
aws s3 mb s3://otro-bucket
Ver solución
bash
aws s3 mb s3://ej02-documentos

Ejercicio 3 — Dar permiso a S3

Autoriza a S3 a invocar tu función.

💡 ¿Sabías que…? — sin esto no pasa nada, y sin error

Es la trampa más costosa de toda la arquitectura de eventos: sin permiso, S3 simplemente no llama, y no queda rastro en ningún registro.

bash
# ejemplo de referencia
aws lambda add-permission --function-name otra --statement-id s3 \
  --action lambda:InvokeFunction --principal s3.amazonaws.com \
  --source-arn arn:aws:s3:::otro-bucket
Ver solución
bash
aws lambda add-permission --function-name ej01-fn --statement-id s3invoke \
  --action lambda:InvokeFunction --principal s3.amazonaws.com \
  --source-arn arn:aws:s3:::ej02-documentos

Ejercicio 4 — Conectar el disparador

Configura el bucket para que avise a la función cuando se cree un objeto.

💡 ¿Sabías que…? — se puede filtrar por tipo de evento

s3:ObjectCreated:* cubre subidas y copias. También existen s3:ObjectRemoved:* y filtros por prefijo o sufijo, para reaccionar solo a ciertos archivos.

bash
# ejemplo de referencia — solo los .pdf
# "Filter": {"Key": {"FilterRules": [{"Name":"suffix","Value":".pdf"}]}}
Ver solución
bash
aws s3api put-bucket-notification-configuration --bucket ej02-documentos \
  --notification-configuration '{"LambdaFunctionConfigurations":[{
    "LambdaFunctionArn":"arn:aws:lambda:us-east-1:000000000000:function:ej01-fn",
    "Events":["s3:ObjectCreated:*"]}]}'

Ejercicio 5 — Dispararlo

Sube un archivo y comprueba que la función se ejecutó.

💡 ¿Sabías que…? — la cadena es asíncrona

aws s3 cp devuelve en cuanto S3 acepta el archivo, sin esperar a la función. Puede tardar unos segundos en aparecer el registro.

bash
# ejemplo de referencia
echo hola > a.txt && aws s3 cp a.txt s3://otro-bucket/
Ver solución
bash
echo "informe" > informe.txt
aws s3 cp informe.txt s3://ej02-documentos/
sleep 8

Ejercicio 6 — Leer los registros

Encuentra la línea que dejó la función.

💡 ¿Sabías que…? — el emulador ordena mal los streams

--order-by LastEventTime --descending se ignora y devuelve el más antiguo. Hay que coger el último de la lista con logStreams[-1].

bash
# ejemplo de referencia
aws logs describe-log-streams --log-group-name /aws/lambda/otra \
  --query 'logStreams[-1].logStreamName' --output text
Ver solución
bash
G=/aws/lambda/ej01-fn
S=$(aws logs describe-log-streams --log-group-name $G \
    --query 'logStreams[-1].logStreamName' --output text)
aws logs get-log-events --log-group-name $G --log-stream-name "$S" \
  --query 'events[*].message' --output text | grep '\[lab\]'
# [lab] llego: informe.txt

Ejercicio 7 — Comprobar el desacoplamiento

Sube dos archivos seguidos y cuenta las invocaciones.

💡 ¿Sabías que…? — un evento por objeto

Cada objeto genera su propio evento. Subir diez archivos son diez invocaciones, posiblemente en paralelo.

bash
# ejemplo de referencia
for i in 1 2; do echo $i > f$i.txt && aws s3 cp f$i.txt s3://otro-bucket/; done
Ver solución
bash
for i in 1 2; do echo "doc $i" > d$i.txt; aws s3 cp d$i.txt s3://ej02-documentos/; done
sleep 10
# dos lineas [lab] llego: en los registros

Ejercicio 8 — Quitar el disparador

Elimina la notificación y comprueba que ya no reacciona.

💡 ¿Sabías que…? — una configuración vacía la borra

No hay comando de borrado: se envía una configuración vacía, que sustituye a la anterior.

bash
# ejemplo de referencia
aws s3api put-bucket-notification-configuration --bucket otro --notification-configuration '{}'
Ver solución
bash
aws s3api put-bucket-notification-configuration --bucket ej02-documentos \
  --notification-configuration '{}'
echo x > x.txt && aws s3 cp x.txt s3://ej02-documentos/
# ya no aparece ninguna linea nueva en los registros

🔵 Nivel 2 — La cola: SQS (9-16)

Ejercicio 9 — Crear una cola

Crea ej09-cola y guarda su URL.

💡 ¿Sabías que…? — la cola se identifica por URL, no por nombre

Casi todos los comandos piden --queue-url. El nombre solo sirve para obtenerla la primera vez con get-queue-url.

bash
# ejemplo de referencia
Q=$(aws sqs create-queue --queue-name otra --query QueueUrl --output text)
Ver solución
bash
Q=$(aws sqs create-queue --queue-name ej09-cola --query QueueUrl --output text)
echo "$Q"

Ejercicio 10 — Enviar y recibir

Envía un mensaje y recógelo.

💡 ¿Sabías que…? — recibir no borra

El mensaje se vuelve invisible durante 30 segundos. Si no lo borras, reaparece. Es a propósito: garantiza que nada se pierde si el consumidor muere.

bash
# ejemplo de referencia
aws sqs send-message --queue-url $Q --message-body "prueba"
aws sqs receive-message --queue-url $Q
Ver solución
bash
aws sqs send-message --queue-url "$Q" --message-body "cita-1" --query 'MessageId' --output text
aws sqs receive-message --queue-url "$Q" --query 'Messages[0].Body' --output text
# cita-1

Ejercicio 11 — Borrarlo de verdad

Recoge un mensaje y elimínalo usando su recibo.

💡 ¿Sabías que…? — el recibo no es el identificador

ReceiptHandle es un identificador de esa recepción concreta, no del mensaje. Si el mensaje reaparece, su recibo cambia.

bash
# ejemplo de referencia
R=$(aws sqs receive-message --queue-url $Q --query 'Messages[0].ReceiptHandle' --output text)
aws sqs delete-message --queue-url $Q --receipt-handle "$R"
Ver solución
bash
R=$(aws sqs receive-message --queue-url "$Q" --query 'Messages[0].ReceiptHandle' --output text)
aws sqs delete-message --queue-url "$Q" --receipt-handle "$R"

Ejercicio 12 — Contar lo que hay pendiente

Averigua cuántos mensajes esperan en la cola.

💡 ¿Sabías que…? — el número es aproximado

Se llama ApproximateNumberOfMessages por algo: SQS es distribuido y el recuento puede ir ligeramente desfasado. Sirve para vigilar tendencias, no para cuadrar cuentas.

bash
# ejemplo de referencia
aws sqs get-queue-attributes --queue-url $Q \
  --attribute-names ApproximateNumberOfMessages --query 'Attributes.*' --output text
Ver solución
bash
aws sqs get-queue-attributes --queue-url "$Q" \
  --attribute-names ApproximateNumberOfMessages \
  --query 'Attributes.ApproximateNumberOfMessages' --output text

Ejercicio 13 — Ver los ajustes de la cola

Consulta el tiempo de invisibilidad y cuánto se retienen los mensajes.

💡 ¿Sabías que…? — 30 segundos y 4 días por defecto

La invisibilidad debe ser mayor que lo que tarda el consumidor en procesar. Si tarda 45 segundos y la invisibilidad son 30, el mensaje reaparece y se procesa dos veces.

bash
# ejemplo de referencia
aws sqs get-queue-attributes --queue-url $Q --attribute-names All
Ver solución
bash
aws sqs get-queue-attributes --queue-url "$Q" --attribute-names All \
  --query 'Attributes.[VisibilityTimeout,MessageRetentionPeriod]' --output text
# 30    345600     (30 segundos, 4 dias)

Ejercicio 14 — Activar el sondeo largo

Configura la cola para que las lecturas esperen hasta 5 segundos.

💡 ¿Sabías que…? — menos llamadas, menos coste

Sin sondeo largo, un consumidor pregunta constantemente y casi siempre recibe «nada». Cada pregunta se factura. Esperar reduce las llamadas drásticamente.

bash
# ejemplo de referencia
aws sqs set-queue-attributes --queue-url $Q --attributes ReceiveMessageWaitTimeSeconds=10
Ver solución
bash
aws sqs set-queue-attributes --queue-url "$Q" \
  --attributes ReceiveMessageWaitTimeSeconds=5

Ejercicio 15 — Enviar varios de golpe

Manda tres mensajes y compruébalos.

💡 ¿Sabías que…? — `send-message-batch` ahorra viajes

Permite hasta 10 mensajes por llamada. Con volumen alto, la diferencia en latencia y coste es notable.

bash
# ejemplo de referencia
for i in 1 2 3; do aws sqs send-message --queue-url $Q --message-body "m$i"; done
Ver solución
bash
for i in 1 2 3; do
  aws sqs send-message --queue-url "$Q" --message-body "cita-$i" >/dev/null
done
aws sqs get-queue-attributes --queue-url "$Q" \
  --attribute-names ApproximateNumberOfMessages --query 'Attributes.*' --output text
# 3

Ejercicio 16 — Vaciar la cola

Bórralo todo de una vez.

💡 ¿Sabías que…? — `purge-queue` tarda hasta 60 segundos

No es instantáneo, y durante ese rato los mensajes enviados también pueden desaparecer. En producción, úsalo con cuidado.

bash
# ejemplo de referencia
aws sqs purge-queue --queue-url $Q
Ver solución
bash
aws sqs purge-queue --queue-url "$Q"

🟡 Nivel 3 — Publicar y suscribir: SNS (17-24)

Ejercicio 17 — Crear un tema

Crea el tema ej17-citas y guarda su ARN.

💡 ¿Sabías que…? — el tema es un punto de reunión

No guarda mensajes: los reparte al instante entre quienes estén suscritos. Si nadie escucha, el mensaje se pierde.

bash
# ejemplo de referencia
T=$(aws sns create-topic --name otro-tema --query TopicArn --output text)
Ver solución
bash
T=$(aws sns create-topic --name ej17-citas --query 'TopicArn' --output text)
echo "$T"
# arn:aws:sns:us-east-1:000000000000:ej17-citas

Ejercicio 18 — Suscribir una cola

Haz que una cola reciba todo lo que se publique en el tema.

💡 ¿Sabías que…? — hace falta el ARN de la cola, no su URL

Es de los pocos sitios donde SQS pide ARN. Se obtiene con get-queue-attributes pidiendo QueueArn.

bash
# ejemplo de referencia
A=$(aws sqs get-queue-attributes --queue-url $Q --attribute-names QueueArn \
    --query 'Attributes.QueueArn' --output text)
Ver solución
bash
A=$(aws sqs get-queue-attributes --queue-url "$Q" --attribute-names QueueArn \
    --query 'Attributes.QueueArn' --output text)
aws sns subscribe --topic-arn "$T" --protocol sqs --notification-endpoint "$A" \
  --query 'SubscriptionArn' --output text

Ejercicio 19 — Publicar un mensaje

Publica en el tema y comprueba que llegó a la cola.

💡 ¿Sabías que…? — SNS envuelve el mensaje

Lo que llega a la cola no es tu texto pelado: es un JSON con Type, MessageId, TopicArn y tu contenido dentro de Message. Hay que desenvolverlo.

bash
# ejemplo de referencia
aws sns publish --topic-arn $T --message "algo paso"
Ver solución
bash
aws sns publish --topic-arn "$T" --message "cita creada" --query 'MessageId' --output text
sleep 3
aws sqs receive-message --queue-url "$Q" --query 'Messages[0].Body' --output text
# {"Type":"Notification","MessageId":"...","Message":"cita creada",...}

Ejercicio 20 — Suscribir una segunda cola

Añade otra cola al mismo tema y comprueba que ambas reciben.

💡 ¿Sabías que…? — esto es lo que SQS no puede hacer

Una cola entrega cada mensaje a un solo consumidor. Para que dos sistemas reciban lo mismo, hace falta un tema delante repartiendo a dos colas.

bash
# ejemplo de referencia
aws sns subscribe --topic-arn $T --protocol sqs --notification-endpoint $ARN2
Ver solución
bash
Q2=$(aws sqs create-queue --queue-name ej20-cola2 --query QueueUrl --output text)
A2=$(aws sqs get-queue-attributes --queue-url "$Q2" --attribute-names QueueArn \
     --query 'Attributes.QueueArn' --output text)
aws sns subscribe --topic-arn "$T" --protocol sqs --notification-endpoint "$A2" >/dev/null
aws sns publish --topic-arn "$T" --message "para las dos" >/dev/null
sleep 3
# ambas colas tienen 1 mensaje

Ejercicio 21 — Listar los suscriptores

Averigua cuántos hay suscritos al tema.

💡 ¿Sabías que…? — el emisor no los consulta nunca

Que se puedan listar es para operar y depurar. La aplicación que publica no debería consultarlos: si lo hace, ha vuelto a acoplarse.

bash
# ejemplo de referencia
aws sns list-subscriptions-by-topic --topic-arn $T --query 'length(Subscriptions)'
Ver solución
bash
aws sns list-subscriptions-by-topic --topic-arn "$T" \
  --query 'length(Subscriptions)' --output text
# 2

Ejercicio 22 — Publicar con asunto

Manda un mensaje con un asunto además del cuerpo.

💡 ¿Sabías que…? — el asunto es para correo

Si el suscriptor es una dirección de correo, --subject es el asunto del mensaje. Para colas viaja como un campo más.

bash
# ejemplo de referencia
aws sns publish --topic-arn $T --subject "Alerta" --message "algo urgente"
Ver solución
bash
aws sns publish --topic-arn "$T" --subject "Cita creada" \
  --message "Paciente 12345601, Cardiologia" --query 'MessageId' --output text

Ejercicio 23 — Desuscribir uno

Quita la segunda cola del tema y comprueba que deja de recibir.

💡 ¿Sabías que…? — quitar un consumidor no toca al emisor

Es la otra cara del desacoplamiento: se añaden y se quitan destinos sin desplegar nada del lado que publica.

bash
# ejemplo de referencia
aws sns unsubscribe --subscription-arn $SUB
Ver solución
bash
SUB=$(aws sns list-subscriptions-by-topic --topic-arn "$T" \
      --query 'Subscriptions[-1].SubscriptionArn' --output text)
aws sns unsubscribe --subscription-arn "$SUB"
aws sns list-subscriptions-by-topic --topic-arn "$T" --query 'length(Subscriptions)' --output text
# 1

Ejercicio 24 — Publicar sin suscriptores

Crea un tema nuevo, publica y observa qué pasa.

💡 ¿Sabías que…? — el mensaje se pierde, sin error

SNS no almacena. Si nadie escucha en ese instante, el mensaje desaparece y publish devuelve éxito igualmente. Por eso el patrón sano es SNS delante de colas: la cola sí guarda.

bash
# ejemplo de referencia
aws sns create-topic --name tema-solitario
Ver solución
bash
T2=$(aws sns create-topic --name ej24-solitario --query TopicArn --output text)
aws sns publish --topic-arn "$T2" --message "nadie me oye" --query 'MessageId' --output text
# devuelve un MessageId... y el mensaje se perdio

🟠 Nivel 4 — El bus de eventos: EventBridge (25-32)

Ejercicio 25 — Ver el bus por defecto

Comprueba qué buses existen.

💡 ¿Sabías que…? — siempre hay uno llamado `default`

Recibe los eventos de los servicios de AWS y los tuyos. Se pueden crear buses adicionales para separar dominios.

bash
# ejemplo de referencia
aws events list-event-buses --query 'EventBuses[*].Name' --output text
Ver solución
bash
aws events list-event-buses --query 'EventBuses[*].Name' --output text
# default

Ejercicio 26 — Crear una regla

Crea una regla que capture los eventos con origen cenate.citas.

💡 ¿Sabías que…? — el patrón mira dentro del evento

Los valores van siempre en lista, aunque sea uno solo: {"source": ["cenate.citas"]}. Es el error de sintaxis más común.

bash
# ejemplo de referencia
aws events put-rule --name otra-regla --event-pattern '{"source":["mi.app"]}'
Ver solución
bash
aws events put-rule --name ej26-regla \
  --event-pattern '{"source":["cenate.citas"]}' \
  --query 'RuleArn' --output text

Ejercicio 27 — Añadir un destino

Haz que la regla envíe lo capturado a tu cola.

💡 ¿Sabías que…? — `FailedEntryCount` es la confirmación

put-targets devuelve cuántos destinos fallaron. Un 0 significa que se registró bien.

bash
# ejemplo de referencia
aws events put-targets --rule otra-regla --targets "Id=1,Arn=$ARN_COLA"
Ver solución
bash
aws events put-targets --rule ej26-regla --targets "Id=1,Arn=$A" \
  --query 'FailedEntryCount' --output text
# 0

Ejercicio 28 — Publicar un evento

Envía un evento al bus y comprueba que llegó a la cola.

💡 ¿Sabías que…? — la forma abreviada no admite JSON

--entries "Source=x,Detail={...}" falla al parsear las llaves. Hay que usar la forma JSON completa, normalmente con file://.

bash
# ejemplo de referencia — el formato que SI funciona
# [{"Source":"mi.app","DetailType":"Algo","Detail":"{\"clave\":\"valor\"}"}]
Ver solución
bash
cat > ev.json <<'EOF'
[{"Source":"cenate.citas","DetailType":"CitaCreada",
  "Detail":"{\"dni\":\"12345601\",\"especialidad\":\"Cardiologia\"}"}]
EOF
aws events put-events --entries file://ev.json --query 'FailedEntryCount' --output text
# 0
sleep 4
aws sqs receive-message --queue-url "$Q" --query 'Messages[0].Body' --output text

Ejercicio 29 — Examinar el sobre del evento

Mira qué campos añadió EventBridge a tu evento.

💡 ¿Sabías que…? — el bus enriquece el evento

Añade id, time, region, account y event-bus-name. Tu contenido queda dentro de detail. Ese sobre estándar es lo que permite enrutar sin conocer la aplicación.

bash
# ejemplo de referencia
aws sqs receive-message --queue-url $Q --query 'Messages[0].Body' --output text | python3 -m json.tool
Ver solución
json
{
  "version": "0",
  "id": "f5940edd-1c4c-455d-a001-6a18437fe543",
  "source": "cenate.citas",
  "detail-type": "CitaCreada",
  "account": "000000000000",
  "time": "2026-08-09T00:07:14Z",
  "region": "us-east-1",
  "detail": { "dni": "12345601", "especialidad": "Cardiologia" },
  "event-bus-name": "default"
}

Ejercicio 30 — Filtrar por contenido

Crea una regla que capture solo las citas de Cardiología.

💡 ¿Sabías que…? — aquí está la potencia del bus

El patrón puede mirar dentro de detail. El emisor publica una vez y cada consumidor recibe solo lo que le interesa, sin filtrar en su código.

json
// ejemplo de referencia
{"detail": {"estado": ["urgente"]}}
Ver solución
bash
aws events put-rule --name ej30-cardio \
  --event-pattern '{"source":["cenate.citas"],"detail":{"especialidad":["Cardiologia"]}}' \
  --query 'RuleArn' --output text

Ejercicio 31 — Comprobar que el filtro descarta

Publica un evento de otra especialidad y comprueba que esa regla no lo captura.

💡 ¿Sabías que…? — lo que no encaja se descarta en silencio

No hay error ni aviso: el bus simplemente no enruta. Al depurar, lo primero es comprobar que el patrón coincide de verdad.

bash
# ejemplo de referencia — cambiar un valor del detail
Ver solución
bash
cat > ev2.json <<'EOF'
[{"Source":"cenate.citas","DetailType":"CitaCreada",
  "Detail":"{\"dni\":\"23456702\",\"especialidad\":\"Neurologia\"}"}]
EOF
aws events put-events --entries file://ev2.json >/dev/null
# la regla ej30-cardio no lo enruta; la ej26-regla si

Ejercicio 32 — Listar reglas y destinos

Muestra las reglas existentes y a dónde envían.

💡 ¿Sabías que…? — el mapa del sistema está aquí

En una arquitectura de eventos, nadie llama a nadie: el mapa de quién reacciona a qué son justamente estas reglas.

bash
# ejemplo de referencia
aws events list-rules --query 'Rules[*].Name' --output text
Ver solución
bash
aws events list-rules --query 'Rules[*].[Name,State]' --output text
aws events list-targets-by-rule --rule ej26-regla --query 'Targets[*].Arn' --output text

🔴 Nivel 5 — Que aguante los fallos (33-40)

Ejercicio 33 — Conectar una cola a una función

Haz que una función consuma automáticamente de una cola.

💡 ¿Sabías que…? — el disparador sondea por ti

El event source mapping consulta la cola constantemente y llama a la función cuando hay mensajes, borrándolos si termina bien. No escribes ningún bucle.

bash
# ejemplo de referencia
aws lambda create-event-source-mapping --function-name otra \
  --event-source-arn $ARN_COLA --batch-size 10
Ver solución
bash
aws lambda create-event-source-mapping --function-name ej33-consumidora \
  --event-source-arn "$A" --batch-size 5 --query 'State' --output text
# Enabled

Ejercicio 34 — Comprobar que consume sola

Envía tres mensajes y verifica que la cola se vacía sin que tú hagas nada.

💡 ¿Sabías que…? — llegan en lote

Con --batch-size 5, la función puede recibir hasta 5 mensajes en un solo evento, dentro de Records. Hay que recorrerlos: procesar solo el primero es un fallo típico.

python
# ejemplo de referencia
for r in event.get("Records", []):
    procesar(r["body"])
Ver solución
bash
for i in 1 2 3; do aws sqs send-message --queue-url "$Q" --message-body "cita-$i" >/dev/null; done
sleep 15
aws sqs get-queue-attributes --queue-url "$Q" \
  --attribute-names ApproximateNumberOfMessages --query 'Attributes.*' --output text
# 0    ← la funcion los consumio

Ejercicio 35 — Crear una cola de mensajes muertos

Crea ej35-dlq para apartar lo que falle repetidamente.

💡 ¿Sabías que…? — es una cola normal

No tiene nada especial: lo que la convierte en cola de mensajes muertos es que otra cola la señala en su RedrivePolicy.

bash
# ejemplo de referencia
aws sqs create-queue --queue-name otra-dlq
Ver solución
bash
DLQ=$(aws sqs create-queue --queue-name ej35-dlq --query QueueUrl --output text)
DA=$(aws sqs get-queue-attributes --queue-url "$DLQ" --attribute-names QueueArn \
     --query 'Attributes.QueueArn' --output text)

Ejercicio 36 — Conectarla a la cola principal

Configura que tras 3 intentos fallidos el mensaje pase a la cola de muertos.

💡 ¿Sabías que…? — sin esto, un mensaje malo bloquea todo

Un mensaje que siempre hace fallar al consumidor reaparece sin fin, consumiendo invocaciones y tapando a los buenos. La cola de muertos lo aparta tras N intentos.

bash
# ejemplo de referencia
--attributes 'RedrivePolicy={"deadLetterTargetArn":"ARN","maxReceiveCount":"5"}'
Ver solución
bash
aws sqs set-queue-attributes --queue-url "$Q" \
  --attributes "RedrivePolicy={\"deadLetterTargetArn\":\"$DA\",\"maxReceiveCount\":\"3\"}"

Ejercicio 37 — Ajustar el tiempo de invisibilidad

Sube la invisibilidad a 60 segundos y explica cuándo hace falta.

💡 ¿Sabías que…? — debe superar el tiempo de proceso

Si la función tarda 45 segundos y la invisibilidad son 30, el mensaje reaparece mientras aún se procesa: se procesa dos veces. La regla práctica es dejarla al menos al doble del tiempo máximo esperado.

bash
# ejemplo de referencia
aws sqs set-queue-attributes --queue-url $Q --attributes VisibilityTimeout=120
Ver solución
bash
aws sqs set-queue-attributes --queue-url "$Q" --attributes VisibilityTimeout=60
aws sqs get-queue-attributes --queue-url "$Q" --attribute-names VisibilityTimeout \
  --query 'Attributes.*' --output text
# 60

Ejercicio 38 — Una cola con orden garantizado

Crea una cola FIFO y observa la diferencia en el nombre.

💡 ¿Sabías que…? — el sufijo es obligatorio

El nombre debe terminar en .fifo. Garantizan orden y entrega única, a cambio de menos rendimiento. Las colas normales no garantizan el orden.

bash
# ejemplo de referencia
aws sqs create-queue --queue-name pedidos.fifo --attributes FifoQueue=true
Ver solución
bash
aws sqs create-queue --queue-name ej38-orden.fifo --attributes FifoQueue=true \
  --query 'QueueUrl' --output text
# http://localhost:4566/000000000000/ej38-orden.fifo

Ejercicio 39 — Diseñar el fan-out completo

Monta un tema que reparta a dos colas, cada una con su función consumidora.

💡 ¿Sabías que…? — es el patrón más usado en producción

SNS reparte, cada cola amortigua a su consumidor. Si uno se cae, su cola acumula sin afectar al otro. Ese aislamiento es la razón de meter colas entre medias.

        ┌──▶ cola A ──▶ funcion A
  TEMA ─┤
        └──▶ cola B ──▶ funcion B
Ver solución
bash
# 1. tema  2. dos colas  3. suscribir ambas  4. un ESM por cola
aws sns publish --topic-arn "$T" --message "evento para todos"
sleep 12
# ambas funciones registran el evento, de forma independiente

Ejercicio 40 — Desmontarlo todo

Elimina disparadores, colas, temas, reglas y funciones.

💡 ¿Sabías que…? — los disparadores se borran aparte

Borrar una cola no elimina el event source mapping que la apuntaba. Queda huérfano reintentando. Hay que borrarlo explícitamente.

bash
# ejemplo de referencia
aws lambda list-event-source-mappings --query 'EventSourceMappings[*].UUID' --output text
Ver solución
bash
for U in $(aws lambda list-event-source-mappings --query 'EventSourceMappings[*].UUID' --output text); do
  aws lambda delete-event-source-mapping --uuid "$U" >/dev/null
done
aws events remove-targets --rule ej26-regla --ids 1 >/dev/null
aws events delete-rule --name ej26-regla
aws sns delete-topic --topic-arn "$T"
aws sqs delete-queue --queue-url "$Q"

❓ Preguntas y respuestas (autoevaluación)

1. ¿Cuál es la prueba de que un sistema está bien desacoplado?

Que puedas añadir un consumidor nuevo sin tocar ni desplegar al emisor.

2. ¿Qué diferencia hay entre SQS y SNS?

La cola entrega cada mensaje a un solo consumidor; el tema lo entrega a todos los suscritos.

3. ¿Por qué recibir un mensaje no lo borra?

Para que reaparezca si el consumidor muere antes de terminar. Sin delete-message, vuelve.

4. ¿Qué pasa si el tiempo de invisibilidad es menor que el de proceso?

El mensaje reaparece mientras aún se procesa y acaba procesándose dos veces.

5. ¿Para qué sirve una cola de mensajes muertos?

Para apartar lo que falla siempre, tras N intentos, y que no bloquee al resto.

6. ¿Qué pasa si publicas en un tema sin suscriptores?

El mensaje se pierde y publish devuelve éxito igual. SNS no almacena; por eso se pone una cola detrás.

7. ¿Qué añade EventBridge sobre SNS?

Reglas que filtran por el contenido del evento y enrutan a destinos distintos.

8. Publicas un evento y la regla no lo captura. ¿Primera sospecha?

Que el patrón no coincide. Recuerda que los valores van en lista: {"source":["x"]}.

9. ¿Qué es un event source mapping?

El disparador que sondea una cola y llama a la función por ti, borrando los mensajes si termina bien.

10. Borras una cola y su función sigue dando errores. ¿Por qué?

El disparador sigue existiendo y reintentando. Hay que eliminarlo aparte.


📎 Apuntes relacionados

🏁 Fin del curso

Has recorrido seis módulos y 240 ejercicios: infraestructura como código, bases de datos gestionadas, caché, API serverless, data lake y arquitectura por eventos.

Lo que queda por delante, si quieres seguir: IAM en profundidad, redes (VPC), contenedores (ECS/EKS) y observabilidad. Y sobre todo, llevar algo de esto a AWS real: el emulador enseña los conceptos, pero la factura enseña a diseñar.

Apuntes de AWS con Floci