CreaRack-SL

Incidente 24-08-2026 · el motor SNMP quedaba corrupto tras cuelgues seguidos — timeout duro + autocuración (Agente 2.21.2→2.21.3)

Cuándo

24-08-2026, mismo día que el incidente hermano del cortacircuitos mixto ([[incident—20260824—breaker-mixto-silencia-snmp-ccib]]) y su hotfix 2.21.1. Tras desplegar 2.21.2 (timeout duro de 20s por petición SNMP, commit d3bd04d7), el Agente Local del CCIB (123 puntos de acceso) mostró en /sentinel/status 90 cuelgues en 4,5 minutos, con snmp_engine_ready=True y cero muestras escritas.

Síntomas visibles

  • /sentinel/status reportaba el motor SNMP como “listo” (snmp_engine_ready=True) pero cada petición agotaba el timeout duro de 20s sin devolver nada.
  • 90 cuelgues en 4,5 minutos: prácticamente todas las peticiones SNMP fallando en cadena, sin un solo éxito intermedio.
  • El único disparador que antes recreaba el motor era ver la excepción "closing transport" — un cuelgue silencioso (timeout puro, sin excepción) nunca la produce, así que el motor corrupto se quedaba corrupto indefinidamente.

Causa raíz

pysnmp 7 comparte el transporte UDP entre todos los motores (engine) que viven en el mismo event loop del proceso. El Agente Local levanta más de un motor SNMP (el del Sentinel y el de deep discovery / lectura de puertos); cuando uno de ellos agota o cierra su transporte, deja al motor del Sentinel con el socket inservible, y todas sus peticiones futuras cuelgan hasta el timeout duro sin lanzar la excepción que el código sabía reconocer.

Fix aplicado

Commit ab41c02a (PR #432, v1.83.3 + Agente 2.21.3, task #263):

  • SNMP_HARD_TIMEOUT baja de 20 a 10 segundos (terminal/agent/config.py) — un lote con cuelgues ya no tarda minutos en devolver el control.
  • Nuevo umbral SNMP_HANG_RECREATE_THRESHOLD = 5: note_snmp_hang() (ahora asíncrono) cuenta cuelgues seguidos y, al llegar a 5 sin ningún éxito entre medias, da el motor por corrupto y lo recrea (recreate_snmp_engine()).
  • note_snmp_ok() reinicia la racha en cuanto una petición SNMP responde con normalidad.
  • Diagnóstico nuevo en /sentinel/status: consecutive_hangs y engine_recreations.
  • Tests: TestEngineSelfHeal en tests/agent/test_snmp_hard_timeout_and_prune.py — verifica que N cuelgues seguidos recrean el motor y que un éxito intermedio corta la racha (suite del Agente completa: 127 verdes).

Lecciones

Este es el segundo hotfix del mismo día sobre el mismo subsistema. 2.21.2 (commit d3bd04d7) ya había puesto un timeout duro para que un cuelgue no bloqueara el lote entero (asyncio.gather esperando indefinidamente a todas las peticiones), pero no cubría el caso de que el motor SUBYACENTE quedara corrupto: entonces todas las peticiones futuras cuelgan igual, una tras otra, hasta agotar el timeout cada vez. Un timeout por petición resuelve “no te quedes esperando para siempre”; no resuelve “deja de intentarlo con una herramienta rota”. Hacían falta las dos capas: cortar cada intento individual (2.21.2) y detectar el patrón de fallos repetidos para actuar sobre la causa (2.21.3).

Preventivos futuros

  • El diagnóstico consecutive_hangs/engine_recreations en /sentinel/status deja visible si el motor se recrea con frecuencia — señal de que otro consumidor del mismo event loop (deep discovery) está interfiriendo con el transporte UDP compartido.
  • Pendiente de evaluar (fuera de alcance de este hotfix): aislar el motor SNMP del Sentinel en su propio transporte o event loop para no depender de la disciplina de otros motores del proceso.

Véase también

  • [[incident—20260824—breaker-mixto-silencia-snmp-ccib]]
  • [[entity—terminal—service—sentinel-tcp-check]]
  • [[entity—terminal—endpoint—agent-metrics-bulk]]
  • [[crearack-tech—architecture—sentinel-mode]]
  • [[crearack-tech—agents—dev-terminal]]
  • [[feature—monitoring—sonda-tcp]]
  • [[concept—monitoring—cns]]