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