ADR-0016: Capa de Resiliencia de Despliegue en Capa Gratuita
- Estado: Accepted
- Fecha: 2026-05-27 (registrado retroactivamente; la capa de resiliencia se publicó en una versión anterior)
- Responsables de la decisión: Waldemar Szemat
Contexto y planteamiento del problema
Section titled “Contexto y planteamiento del problema”La demo corre en Google Cloud Run como una única instancia scale-to-zero (ADR-0007); la misma imagen también corre en el objetivo secundario Hugging Face Spaces CPU Basic. La URL pública de la demo se comparte abiertamente. Una breve ráfaga de visitantes curiosos (una publicación que es recogida, una mención en una conferencia) puede disparar el tráfico más rápido de lo que el agente puede responder.
Sin protección, la instancia encola turnos hasta que o bien el bucle de eventos se queda atrás y los tiempos de espera caen en cascada, o bien el proxy de borde de la plataforma devuelve 502 Bad Gateway. Ambos resultados convierten un momento público en una demo rota.
¿Cómo protegemos a la instancia de las ráfagas de solicitudes concurrentes manteniendo el costo operativo de cerca de $0/mes a escala de demo y la simplicidad de una única instancia, sin introducir Redis?
Factores de la decisión
Section titled “Factores de la decisión”- Presupuesto operativo de cerca de $0/mes a escala de demo (ADR-0007): sin Redis, sin servicio de limitación de tasa administrado.
- Simplicidad de una única instancia: el diseño de despliegue es una
instancia (
--max-instances 1); compartir el estado de limitación de tasa entre instancias no es una preocupación actual. - Semántica de reintento transparente: el cliente (la aplicación) debe
saber cuándo reintentar.
Retry-Afteres la cabecera de carga estructural. - La demo sobrevive a ráfagas de entrada idéntica: cuando diez espectadores hacen clic en el mismo escenario de ejemplo, la instancia debería computar la respuesta una sola vez.
Opciones consideradas
Section titled “Opciones consideradas”- Opción A: Sin protección. La instancia maneja cada solicitud hasta que se cae.
- Opción B: Limitador de tasa de ventana deslizante respaldado por Redis + caché de respuestas.
- Opción C: Limitador de tasa de ventana deslizante en proceso + caché de respuestas TTL en proceso, ambos basados en una firma de solicitud normalizada. Memoria acotada.
- Opción D: Usar un límite de tasa a nivel de CDN (Cloudflare frente a la plataforma de hosting).
Resultado de la decisión
Section titled “Resultado de la decisión”Opción elegida: Opción C — una capa de resiliencia en proceso con un limitador de tasa de ventana deslizante y una caché de respuestas TTL, ambos acotados y residentes en memoria. La razón individual de mayor carga estructural es el presupuesto de cerca de $0/mes: cualquier dependencia externa para la limitación de tasa viola la postura de despliegue. El diseño en proceso también coincide con la verdad de una única instancia: no hay una segunda instancia con la cual coordinarse.
Comportamiento:
- El limitador de tasa se basa en la IP del cliente (consciente del proxy, de
modo que la cabecera
X-Forwarded-Forse respeta detrás del proxy inverso de la plataforma). Una ventana deslizante con un conteo acotado de solicitudes por ventana rechaza las ráfagas con HTTP 429 y una pistaRetry-After. - La caché de respuestas se basa en una tupla normalizada de (texto, configuración regional, modelo). Un TTL corto mantiene la memoria acotada. Las entradas idénticas dentro de la ventana del TTL devuelven la respuesta en caché, evitando un gasto redundante de LLM.
- La caché NUNCA se usa para un turno pausado (HITL): un borrador pausado no es una respuesta final y no debe servirse a una sesión diferente como si lo fuera.
Confirmación
Section titled “Confirmación”- El limitador de tasa y la caché están implementados en un módulo de resiliencia dedicado.
- Las pruebas unitarias cubren: la decisión de límite de tasa bajo ráfaga, un
acierto de caché ante entrada idéntica, un fallo de caché ante una
configuración regional o un modelo diferente, sin caché en los turnos
pausados, y la propagación de
Retry-After. - El limitador se aplica antes del trabajo del agente, y la caché se aplica alrededor de la invocación del agente.
Consecuencias
Section titled “Consecuencias”Positivas
Section titled “Positivas”- La demo sobrevive a las ráfagas de tráfico sin infraestructura externa.
- El tráfico de entrada idéntica (el patrón de “todos hicieron clic en el mismo ejemplo”) cuesta cero gasto de LLM en las repeticiones dentro del TTL de la caché.
- La semántica de HTTP 429 +
Retry-Afteres transparente y amable con el cliente. - El presupuesto de cerca de $0/mes a escala de demo se preserva.
Negativas
Section titled “Negativas”- La protección es por instancia. Un despliegue con escalado horizontal (múltiples instancias detrás de un balanceador de carga) necesitaría externalizar el limitador y la caché a Redis. El diseño es honesto sobre esta limitación, registrada como una brecha de preparación para producción en el informe de rendimiento.
- El reinicio de la instancia pierde el estado de la caché. El tráfico de arranque en frío paga el costo completo de LLM hasta que la caché se calienta.
- El limitador basado en IP es grueso: un NAT corporativo presenta a toda la organización como una única IP. El conteo de ventana acotada debe ajustarse para no penalizar el tráfico legítimo con NAT; el ajuste actual es intencionalmente indulgente.
Neutrales
Section titled “Neutrales”- La decisión de límite de tasa agrega una verificación en proceso por solicitud. El costo de latencia es de menos de un milisegundo.
- La caché agrega estado en memoria. Un TTL acotado mantiene la huella de memoria manejable dentro de la memoria de la instancia.
Ventajas y desventajas de las opciones
Section titled “Ventajas y desventajas de las opciones”Opción A: Sin protección
Section titled “Opción A: Sin protección”- Buena, porque cero infraestructura.
- Mala, porque la instancia se cae bajo tráfico de ráfaga.
- Mala, porque no hay semántica de 429 +
Retry-After: el cliente ve un 502 del proxy de la plataforma.
Opción B: Limitador + caché respaldados por Redis
Section titled “Opción B: Limitador + caché respaldados por Redis”- Buena, porque sobrevive al escalado horizontal multi-instancia.
- Mala, porque agrega una dependencia externa (instancia de Redis, gestión de secretos, salto de red).
- Mala, porque entra en conflicto con el presupuesto de cerca de $0/mes.
- Mala, porque es sobreingeniería para la realidad de una única instancia.
Opción C (elegida): Limitador + caché en proceso
Section titled “Opción C (elegida): Limitador + caché en proceso”- Buena, porque no hay dependencia externa.
- Buena, porque coincide con la verdad de una única instancia.
- Buena, porque es explícita, comprobable y autocontenida.
- Mala, porque no escala más allá de una instancia (reconocido).
Opción D: Límite de tasa a nivel de CDN
Section titled “Opción D: Límite de tasa a nivel de CDN”- Buena, porque delega la protección al borde de Cloudflare.
- Mala, porque no cubre la necesidad de la caché de respuestas.
- Mala, porque en el objetivo secundario gratuito (Hugging Face Spaces) el tráfico se enruta directamente, sin control de DNS / dominio para poner Cloudflare al frente.
Más información
Section titled “Más información”- ADR-0007 — objetivo de despliegue y el presupuesto de cerca de $0/mes
- ADR-0014 — la capa complementaria de respaldo en cascada
- MADR 4.0.0: https://adr.github.io/madr/