🐘 Caso 04 - PHP 8.3 resiliente vs legacy#
Implementación operativa del caso 04 para contrastar retries agresivos contra una variante que contiene la falla.
⬅️ Caso 04 · ⚖️ Comparativa de los 7 stacks · 🐘 Perfil de PHP · 🧬 Todos los perfiles
🎯 Qué resuelve#
Modela una API de cotización que depende de un proveedor externo de carriers:
quote-legacyrepite timeouts varias veces y amplifica la carga saliente;quote-resilientusa timeout corto, backoff, circuit breaker y fallback cacheado.
💻 Interfaz Visual Nativa#
Al abrir la ruta raíz en tu navegador (Accept: text/html), este caso inyecta automáticamente un Dashboard visual interactivo renderizado en Vanilla JS/CSS. Esto permite observar las métricas y efectos simulados en tiempo real sin perder la capacidad de responder a consultas JSON de CLI o Postman.
💼 Por qué importa#
Este caso deja visible un patrón muy real: una dependencia lenta no solo agrega latencia, también puede degradar al servicio llamador cuando los retries no tienen límites sanos.
🔬 Análisis Técnico de la Implementación (PHP)#
El diseño de resiliencia requiere manejo de tiempo explícito y algoritmos de retroceso probabilístico para evitar la saturación de recursos síncronos en PHP-FPM.
- Punto Crítico (
legacy): La políticalegacyutiliza un bucle persistente de reintentos con untimeout_msfijo y elevado, sin tiempo de espera entre intentos (backoff_base_ms: 0). Bajo una falla de dependencia, esto provoca que PHP mantenga el descriptor de socket abierto y el proceso bloqueado durante segundos medianteusleep()acumulativo, agotando rápidamente el pool de workers disponibles y amplificando la carga hacia el proveedor (tormenta de reintentos). - Resguardo Nativo (
resilient): Implementa el algoritmo de Exponential Backoff con Jitter. La funcióncalculateBackoffMs()utiliza la expresión aritmética($baseMs * (2 ** max(0, $attempt - 1))) + random_int(15, 45), donde2 ** nescala el tiempo exponencialmente yrandom_int()añade entropía para desfasar los picos de reintento. Adicionalmente, el Circuit Breaker se valida de forma atómica comparando el timestamp actual con la ventana de apertura mediantestrtotime($provider['opened_until']) > time(), permitiendo que PHP aborte la ejecución antes de iniciar el I/O si el sistema se sabe degradado, protegiendo así el Lead Time del usuario.
🧱 Servicio#
app-> API PHP 8.3 con escenarios de proveedor estable, lento, caído o intermitente.
🚀 Arranque#
docker compose -f compose.yml up -d --buildComo consumir (dos opciones)#
Hub PHP (recomendado, 8100 en compose.root.yml): este caso queda servido en http://localhost:8100/04/... junto a los otros 11 casos.
Modo aislado (814 en este compose.yml): levanta solo este caso, util cuando la medicion necesita procesar limpio (sin otros casos compartiendo runtime).
🔎 Endpoints#
curl http://localhost:8100/04/
curl http://localhost:8100/04/health
curl "http://localhost:8100/04/quote-legacy?scenario=provider_down&customer_id=42&items=3"
curl "http://localhost:8100/04/quote-resilient?scenario=provider_down&customer_id=42&items=3"
curl http://localhost:8100/04/dependency/state
curl http://localhost:8100/04/incidents?limit=10
curl http://localhost:8100/04/diagnostics/summary
curl http://localhost:8100/04/metrics
curl http://localhost:8100/04/metrics-prometheus
curl http://localhost:8100/04/reset-lab🧪 Escenarios útiles#
provider_down-> ideal para ver tormenta de retries y fallback.flaky_provider-> muestra retry útil versus retry agresivo.burst_then_recover-> permite ver recuperación parcial con distinto costo.slow_provider-> enfatiza la necesidad de deadlines explícitos.
🧭 Qué observar#
- cuántos intentos y retries hace cada modo;
- si el circuito se abre y evita seguir golpeando la dependencia;
- cuándo aparece respuesta degradada con fallback en vez de cascada de fallas;
- cómo cambia la latencia total entre
legacyyresilient.
⚖️ Nota de honestidad#
No reemplaza una integración real ni una malla de servicios. Sí reproduce el comportamiento operativo que importa aquí: timeouts, retries, circuit breaker, fallback y el costo de una mala postura de resiliencia.