Módulo 1: What Is Sre And Reliability As A Feature
4. Manos a la obra: leyendo Andes Cargo como lo leería un SRE
Descripción
cloud-security-and-guardrails-guide ya recorrió andes-cargo-infra/ preguntando "¿esto es peligroso?". finops-and-cost-guardrails-guide recorrió el mismo terreno preguntando "¿esto genera un cargo cada mes?". Esta lección hace el tercer recorrido, con una pregunta distinta a las dos anteriores y que ninguna guía de este ecosistema hizo todavía: ¿qué puede fallar aquí, y qué se enteraría de que falló? No es una auditoría de seguridad —esa ya está hecha— ni un inventario de costo —también hecho—. Es la primera lectura de Andes Cargo con ojos de SRE: cada recurso, cada configuración, evaluado por su exposición al fallo, no por su vulnerabilidad ni por su precio.
Esta lección tiene dos partes con dos niveles de certeza distintos, con la misma honestidad que sostiene el resto de este ecosistema. Leer la configuración real —los valores exactos de concurrencia, timeout, modo de capacidad, región— es completamente literal: son los números con los que las guías anteriores dejaron el sistema. Confirmar esos números con awslocal es representativo: este entorno de escritura no tiene LOCALSTACK_AUTH_TOKEN exportado, así que el contenedor de LocalStack no arranca. La salida que vas a leer es la que producirían esos comandos contra la infraestructura ya aplicada, reconstruida campo por campo a partir de lo que aws-core-services-guide y aws-serverless-and-containers-guide ya confirmaron corriendo de verdad — nunca inventada.
Conexión con el módulo
La lección 3 te dio el vocabulario del error budget. Antes de poder definir un SLI real (Módulo 2) o instrumentar observabilidad (Módulo 3), necesitas saber qué partes del sistema pueden fallar, sin ese conocimiento cualquier SLI que elijas sería una adivinanza. Esta lección construye ese inventario de riesgo. Las lecciones 5 y 6 van a mostrar, con el incidente Claude Code, qué pasa cuando exactamente este tipo de pregunta no se hizo a tiempo.
Verificación 1 — La función Lambda: get-function, leída para exposición al fallo
awslocal lambda get-function --function-name process-shipment-manifest
Qué esperar (representativo — reconstruido campo por campo del estado real que aws-serverless-and-containers-guide, Módulo 2, proyecto, ya confirmó corriendo; CodeSha256, LastModified y RevisionId son tu valor variable, el resto es literal):
{
"Concurrency": {
"ReservedConcurrentExecutions": 5
},
"Configuration": {
"FunctionName": "process-shipment-manifest",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:process-shipment-manifest",
"Runtime": "python3.13",
"Role": "arn:aws:iam::000000000000:role/LambdaManifestProcessorRole",
"Handler": "handler.lambda_handler",
"Timeout": 10,
"MemorySize": 128,
"Environment": {
"Variables": {
"CARRIER_API_KEY_SECRET_NAME": "andes-cargo/carrier-api-key"
}
},
"Layers": [
{
"Arn": "arn:aws:lambda:us-east-1:000000000000:layer:shipment-utils-layer:1"
}
],
"State": "Active",
"LastUpdateStatus": "Successful"
}
}
Una auditoría de seguridad lee este JSON preguntando "¿el rol tiene permiso de más?". Una auditoría de costo lee "¿cuánto cuesta cada GB-segundo a 128 MB?". Una lectura de SRE hace tres preguntas distintas:
ReservedConcurrentExecutions: 5— ¿qué pasa en la sexta invocación simultánea? Esta es una decisión de diseño real deaws-serverless-and-containers-guide, pensada para proteger tanto la disponibilidad de la función como a una API externa de transportista de un pico de tráfico. Pero un techo de concurrencia es, al mismo tiempo, un límite de disponibilidad: si Andes Cargo alguna vez recibe seis manifiestos al mismo instante, el sexto se regula (throttling) — no falla con un error de código, falla con un error de capacidad, un tipo de fallo completamente distinto que necesita su propia señal para detectarse.Timeout: 10— ¿qué pasa si un manifiesto tarda más de 10 segundos en procesarse? El techo protege contra una función colgada indefinidamente, pero también es un límite duro: si algún manifiesto futuro, más grande o más complejo, necesita 11 segundos, la invocación se corta a la fuerza, sin importar cuán cerca estuviera de terminar.- El trigger de S3 invoca esta función de forma asíncrona — ¿a dónde va un evento que falla? La documentación oficial de AWS Lambda es precisa sobre este punto exacto: "By default, Lambda retries a failed asynchronous invocation up to two times." — dos reintentos automáticos, sin que nadie tenga que configurar nada. Pero después del segundo reintento fallido, sin una cola de mensajes fallidos (dead-letter queue) configurada específicamente sobre esta invocación asíncrona, el evento simplemente se descarta. Ninguno de los campos de este JSON confirma si esa cola existe para esta ruta de invocación específica — es exactamente el tipo de pregunta que esta lección deja abierta, y que la observabilidad del Módulo 3 va a poder contestar con evidencia, no con inferencia.
Verificación 2 — La tabla DynamoDB: describe-table, leída para exposición al fallo
awslocal dynamodb describe-table --table-name Shipments
Qué esperar (representativo; ItemCount y TableSizeBytes son tu valor variable —y, como ya confirmaste en aws-serverless-and-containers-guide, ItemCount ni siquiera es un conteo en tiempo real—; el resto es literal):
{
"Table": {
"TableName": "Shipments",
"KeySchema": [
{
"AttributeName": "shipmentId",
"KeyType": "HASH"
}
],
"TableStatus": "ACTIVE",
"ItemCount": 6,
"TableSizeBytes": 912,
"TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/Shipments",
"BillingModeSummary": {
"BillingMode": "PAY_PER_REQUEST"
}
}
}
La pregunta de SRE sobre este mismo JSON: PAY_PER_REQUEST significa que DynamoDB escala automáticamente, sin que nadie reserve capacidad — pero "automático" no significa "sin límite ni condición". La documentación oficial de DynamoDB es específica sobre exactamente cuándo ese piloto automático deja de alcanzar:
"On-demand capacity mode instantly accommodates up to double the previous peak traffic on a table. [...] However, throttling can occur if you exceed double your previous peak within 30 minutes."
Traducido al caso de Andes Cargo: si el tráfico normal de Shipments ronda, digamos, 10 escrituras por segundo en su pico histórico, la tabla puede absorber instantáneamente hasta 20 escrituras por segundo sin ningún problema. Pero si un evento inesperado —una promoción, una migración de datos, un reintento masivo mal diseñado— empuja el tráfico a 50 escrituras por segundo en cuestión de minutos, más del doble del pico anterior, en menos de 30 minutos, la tabla puede empezar a regular solicitudes, devolviendo errores de capacidad a pesar de estar en modo on-demand. Ningún recurso de andes-cargo-infra/, hoy, mide si esto ya pasó alguna vez, ni alertaría si volviera a pasar — otra pregunta que esta lección deja identificada, no resuelta.
Verificación 3 — El bucket S3: get-bucket-location, leída para exposición al fallo
awslocal s3api get-bucket-location --bucket andes-cargo-shipment-docs
Qué esperar (representativo — literal: para un bucket creado en us-east-1, la documentación oficial de AWS es explícita en que el valor correcto es null, no la cadena "us-east-1"):
{
"LocationConstraint": null
}
Este es el resultado más pequeño de los tres comandos de esta lección, y la pregunta de SRE que se deriva de él es, al mismo tiempo, la más grande de todo este módulo: todo Andes Cargo —el bucket, la función, la tabla— vive en una sola región. Ningún recurso replica a otra región, ningún mecanismo de failover existe si us-east-1 completo deja de responder. Esto no es un error de diseño de las guías anteriores —una arquitectura multi-región para un sistema de tracking de envíos en etapa inicial sería, siguiendo exactamente la lógica de la lección 3 de este módulo, un costo de ingeniería completamente injustificado frente al riesgo real—, pero es un hecho que un SRE necesita tener nombrado con precisión, no descubierto por sorpresa. La lección 5 de este módulo va a nombrar, con cifras reales, exactamente qué pasa cuando us-east-1 completo tiene un mal día.
El inventario de riesgo completo: qué se identificó, y quién lo resuelve
| Recurso | Lo que confirma el comando | El riesgo de SRE que expone | Quién lo mide/resuelve en esta guía |
|---|---|---|---|
process-shipment-manifest | ReservedConcurrentExecutions: 5 | Una sexta invocación simultánea se regula — sin ninguna alerta hoy | Módulo 3 (métricas de Throttles), Módulo 4 (alerta) |
process-shipment-manifest | Timeout: 10 | Una invocación que exceda 10s se corta a la fuerza | Módulo 3 (duración real, medida) |
process-shipment-manifest (trigger S3, asíncrono) | Reintento automático ×2, sin DLQ confirmada en esta ruta | Un evento que falla dos veces se pierde en silencio, sin evidencia | Módulo 3 (logs), Módulo 7 (runbook) |
Shipments | BillingModeSummary.BillingMode: PAY_PER_REQUEST | Regulación posible si el tráfico supera el doble del pico anterior en menos de 30 minutos | Módulo 2 (SLI de disponibilidad la mediría) |
Shipments | Sin deletion protection confirmada | Nada evita, hoy, un delete-table o un destroy accidental — el tema exacto del incidente de las lecciones 5 y 6 | Módulo 7 (intento de backup/restore) |
andes-cargo-shipment-docs (vía la función) | LocationConstraint: null (us-east-1) | Una sola región, sin failover — el mismo tipo de riesgo que el outage de us-east-1 (lección 5) hizo real para media internet | Nombrado, no resuelto — fuera del alcance $0 de esta guía |
Ninguna fila de esta tabla es una vulnerabilidad de seguridad —ese inventario ya lo hizo cloud-security-and-guardrails-guide— ni un driver de costo —ese ya lo hizo finops-and-cost-guardrails-guide—. Cada fila es, específicamente, una pregunta sobre qué pasa cuando algo falla y quién se entera. Esa es, en una tabla, la diferencia real entre las tres lecturas que este ecosistema ya hizo del mismo sistema.
Errores comunes
Repetir la auditoría de seguridad o de costo con otro nombre (de superposición). Qué pasa: alguien, al hacer esta lectura, termina anotando hallazgos como "el bucket no tiene bloqueo de acceso público" o "la tabla en PAY_PER_REQUEST puede salir cara" — hallazgos válidos, pero que ya pertenecen a otras dos guías. Cómo detectarlo: si tu inventario de esta lección menciona seguridad o costo, en vez de disponibilidad. Cómo corregirlo: la pregunta única de esta lección es "¿qué pasa cuando esto falla, y quién se entera?" — nunca "¿esto es inseguro?" ni "¿esto es caro?". Si un hallazgo no tiene una respuesta clara a "cómo se detectaría el fallo", no pertenece a este inventario.
Concluir que un techo de concurrencia de 5 es "poco" o "mal configurado" sin contexto (de intuición sin datos). Qué pasa: alguien ve ReservedConcurrentExecutions: 5 y asume que es un número arbitrariamente bajo, sin ninguna evidencia de cuál es el tráfico real de Andes Cargo. Cómo detectarlo: si tu conclusión es "deberían subir ese número" sin haber medido cuántas invocaciones simultáneas ocurren de verdad. Cómo corregirlo: esta lección identifica el riesgo —qué pasa en la invocación número seis—, no lo resuelve ni lo juzga. aws-serverless-and-containers-guide ya justificó ese número con una razón de diseño explícita (proteger tanto la función como una API externa). El Módulo 3 de esta guía es el que va a traer datos reales de cuántas invocaciones simultáneas ocurren, antes de que nadie decida si 5 es el número correcto.
Tratar esta lectura como el final del trabajo, no como el inicio (de expectativa). Qué pasa: alguien termina esta lección pensando que ya "cubrió" la confiabilidad de Andes Cargo, porque identificó los riesgos. Cómo detectarlo: si no puedes nombrar, para cada fila de la tabla de riesgo de esta lección, qué módulo específico de esta guía la mide o la resuelve. Cómo corregirlo: esta lección es exactamente lo que fue la lección 4 de finops-and-cost-guardrails-guide para el costo, o la lección 4 de cloud-security-and-guardrails-guide para la seguridad —un inventario, no una solución—. La tabla de esta lección existe, específicamente, como un mapa hacia el resto de la guía: cada fila tiene un módulo de destino, ninguna fila se cierra aquí.
Ejercicios
Ejercicio 1 — Clasifica un hallazgo hipotético. Si notaras que andes-cargo-app-server (la instancia EC2 heredada de aws-core-services-guide) no tiene ninguna alarma de CloudWatch configurada sobre su estado de salud, ¿ese hallazgo pertenece a esta lección (SRE), a cloud-security-and-guardrails-guide (seguridad), o a finops-and-cost-guardrails-guide (costo)? Justifica.
Ver solución
Pertenece a esta lección (SRE). La ausencia de una alarma de salud no expone ningún riesgo de seguridad (no abre acceso no autorizado) ni de costo (no genera ningún cargo adicional o evitable) — expone exactamente el tipo de riesgo que esta lección busca: si la instancia deja de responder, nadie se entera hasta que un humano lo note por accidente. Es el mismo patrón que las filas de la tabla de esta lección: "¿qué pasa cuando falla, y quién se entera?" es una pregunta de disponibilidad, el terreno exclusivo de SRE.
Ejercicio 2 — Explica por qué ReservedConcurrentExecutions: 5 no es, por sí mismo, ni bueno ni malo. Un compañero afirma que cualquier techo de concurrencia reservada es "una mala práctica" porque limita la disponibilidad del sistema. ¿Estás de acuerdo?
Ver solución
En desacuerdo, con matices. Un techo de concurrencia sí introduce un límite de disponibilidad —la sexta invocación simultánea se regula, como identificó esta lección—, pero también protege contra el escenario opuesto: sin ningún techo, un pico de tráfico descontrolado en process-shipment-manifest podría consumir toda la concurrencia disponible de la cuenta, afectando a otras funciones Lambda que compartan la misma cuenta y región. aws-serverless-and-containers-guide documentó esta razón exacta al fijar el número en 5: proteger tanto la disponibilidad de esta función como la de una API externa de transportista frente a un pico. La pregunta correcta no es "¿debería existir un techo?" —casi siempre debería—, sino "¿este número específico refleja el tráfico real esperado, medido con datos, no con una suposición?" — exactamente la pregunta que el Módulo 3 de esta guía va a poder contestar con evidencia.
Ejercicio 3 — Diseña la pregunta de SRE para un recurso nuevo, sin ejecutar nada. Si Andes Cargo agregara mañana una cola SQS entre S3 y Lambda (para desacoplar la subida de manifiestos del procesamiento), ¿qué pregunta de SRE —siguiendo el patrón de esta lección, no el de seguridad ni de costo— harías sobre esa cola nueva?
Ver solución
Siguiendo el mismo patrón de las tres verificaciones de esta lección, la pregunta correcta sería sobre la política de redirección de mensajes fallidos (redrive policy) y el tiempo de visibilidad de la cola: ¿cuántas veces se reintenta un mensaje que Lambda no puede procesar antes de moverlo a una cola de mensajes fallidos?, ¿y si esa cola de mensajes fallidos existe, algo o alguien la está observando, o los mensajes se acumulan ahí sin que nadie se entere? La pregunta de seguridad sería sobre permisos de acceso a la cola; la de costo, sobre el precio por millón de solicitudes. La de SRE, siguiendo el patrón exacto de esta lección, es siempre la misma forma: "¿qué pasa cuando esto falla, y quién se entera?".
Resumen y siguiente paso
En esta lección leíste tres recursos centrales de Andes Cargo —la función process-shipment-manifest, la tabla Shipments, el bucket andes-cargo-shipment-docs— con una pregunta que ninguna guía anterior de este ecosistema hizo: no seguridad, no costo, sino exposición al fallo. Identificaste seis riesgos concretos —un techo de concurrencia sin alerta, un timeout sin métrica de duración real, reintentos asíncronos sin cola de fallo confirmada, un modo de capacidad con una condición específica de regulación, ausencia de protección de eliminación, y una sola región sin failover— y ubicaste, para cada uno, exactamente qué módulo de esta guía lo va a medir o resolver.
Antes de avanzar deberías poder: explicar la pregunta única que distingue esta lectura de la de seguridad y de costo; nombrar los seis riesgos identificados y en qué campo exacto del JSON de cada comando se descubrieron; y explicar por qué esta lección es un inventario, no una solución.
Las lecciones 5 y 6 traen el caso que hace que este inventario deje de sentirse teórico: el incidente Claude Code destroy, y la primera vez, en toda esta guía, que se mide con un número real.
Recursos
- AWS Lambda Developer Guide — Understanding retry behavior in Lambda — fuente exacta de los dos reintentos automáticos por defecto en invocación asíncrona, citada en la Verificación 1.
- Amazon DynamoDB Developer Guide — On-demand capacity mode — fuente exacta de la condición de regulación al doble del pico anterior en 30 minutos, citada en la Verificación 2.
- AWS CLI —
s3api get-bucket-locationCommand Reference — fuente exacta del valornullpara buckets enus-east-1, citada en la Verificación 3. aws-serverless-and-containers-guide, Módulo 2, proyecto — el estado real y verificado deprocess-shipment-manifest(concurrencia, layer, alias) que esta lección reconstruye.cloud-security-and-guardrails-guide, Módulo 1 yfinops-and-cost-guardrails-guide, Módulo 1 — las dos lecturas anteriores del mismo sistema, con preguntas distintas a la de esta lección.