🐍 Caso 05 — Python 3.12 con presion de memoria comparada#
Implementacion operativa del caso 05 para mostrar como una fuga silenciosa degrada un proceso largo frente a una variante que controla su estado.
⬅️ Caso 05 · ⚖️ Comparativa de los 7 stacks · 🐍 Perfil de Python · 🧬 Todos los perfiles
🎯 Que resuelve#
Modela un proceso de lotes que recibe documentos y payloads de tamano variable:
batch-legacyretiene buffers, hace crecer el estado acumulado y deja subir la presion de recursos;batch-optimizedlimita el cache, limpia estado tras cada item y mantiene el proceso dentro de umbrales sanos.
💼 Por que importa#
Este caso sirve para evidenciar un problema comun en incidentes largos: no siempre hay una excepcion clara. Muchas veces el servicio solo se va degradando hasta que alguien lo reinicia. La presion de memoria es silenciosa hasta que no lo es.
🔬 Analisis Tecnico de la Implementacion (Python)#
Python tiene recolector de basura automatico, pero no elimina el problema de fugas: una referencia activa impide que gc reclame el espacio, sin importar cuanto tiempo pase.
- Problema de Fragmentacion y Fugas (
legacy): La funcionrun_batch_legacy()itera sobre cada item y genera un payload conb64encode(os.urandom(size_bytes)).decode(), luego lo acumula en una lista globalretained_bufferssin ningun limite. Cada llamada a la ruta agregaitems * size_kbKB al estado del proceso. Al mantener referencias vivas enretained_buffers, el recolector de basura de Python no puede liberar esos bloques: el objeto existe y tiene al menos un referenciador. Elretained_kbcrece de formaO(N*calls)hasta que el servidor alcanza el umbralcritical(16384 KB) y empieza a devolver HTTP 503. - Ciclo de Memoria Constante (
optimized): Implementa una politica de Eviccion FIFO con complejidad espacialO(1). En lugar de retener los buffers base64, la funcion calculahashlib.sha256(payload.encode()).hexdigest()y lo guarda como identificador compacto (64 bytes, nosize_kbKB). Para mantener el cache acotado a 24 entradas maximas, usaif len(digest_cache) > 24: digest_cache.pop(next(iter(digest_cache))). Tras procesar cada item, llama explicitamente adel payloadpara eliminar la referencia local, permitiendo que el GIL libere el bloque en el siguiente ciclo del recolector. Elretained_kbpermanece cerca de cero independientemente de cuantos batches se procesen.
🧱 Servicio#
app→ API Python 3.12 con estado local acumulado por modo y metricas de presion.
🚀 Arranque#
docker compose -f compose.yml up -d --buildPuerto local: 835 (modo aislado, ver opciones abajo).
Como consumir (dos opciones)#
Hub Python (recomendado, 8200 en compose.python.yml): este caso queda servido en http://localhost:8200/05/... junto a los otros 11 casos.
Modo aislado (835 en este compose.yml): levanta solo este caso, util cuando la medicion necesita procesar limpio (sin otros casos compartiendo runtime).
🔎 Endpoints#
curl http://localhost:8200/05/
curl http://localhost:8200/05/health
curl "http://localhost:8200/05/batch-legacy?items=50&size_kb=128"
curl "http://localhost:8200/05/batch-optimized?items=50&size_kb=128"
curl http://localhost:8200/05/state
curl "http://localhost:8200/05/runs?limit=10"
curl http://localhost:8200/05/diagnostics/summary
curl http://localhost:8200/05/metrics
curl http://localhost:8200/05/metrics-prometheus
curl http://localhost:8200/05/reset-lab🧪 Escenarios utiles#
items=50&size_kb=128→ varias llamadas seguidas para ver como suberetained_kben legacy.items=100&size_kb=64→ lotes mas grandes para alcanzar el umbralcriticaly provocar HTTP 503.- Llamar
batch-optimizeden las mismas condiciones y compararretained_kbconstante.
🧭 Que observar#
- como sube
retained_kbenbatch-legacytras varias ejecuciones y nunca baja; - si
retained_kbse mantiene cerca de 0 enbatch-optimizedsin importar cuantos batches; - cuando
pressure_levelpasa dehealthyawarningocritical; - la diferencia entre
peak_request_kb(por llamada) y el estado retenido acumulado.
⚖️ Nota de honestidad#
Python tiene GC automatico, pero no elimina el problema de retener referencias activas. El laboratorio reproduce la senal operativa importante: crecimiento silencioso de estado, degradacion progresiva y necesidad de limites y limpieza explicita.