Volver a la wiki

Servicio reopen_group — Reapertura de grupos resueltos por correlación nueva

Descripción

Función: reopen_group(group: IncidentGroup) -> None

Ubicación: monitoring/services/correlation_service.py (líneas ~126–133)

Cuando un nuevo insight se correlaciona a un grupo que ya estaba resuelto, este servicio reabre el grupo automáticamente limpiando resolved_at.

Se invoca desde correlate_new_insight() cuando la lógica de correlación asigna un insight a un grupo existente que ya está cerrado.


Firma y comportamiento

def reopen_group(group):
    """Reopen a resolved group when a new insight correlates into it."""
    if group.status == "resolved":
        group.status = "open"
        group.resolved_at = None
        group.save(update_fields=["status", "resolved_at"])
        logger.info(f"Reopened incident group '{group.title}' (new correlated insight)")

Semántica

Un grupo resuelto significa “no queda nada accionable” en ese momento. Si aparece un nuevo insight correlacionado (misma red, mismo target, mismo patrón), la situación cambió: hay trabajo nuevo.


Integración en correlate_new_insight()

La función de correlación intenta 3 reglas (en orden):

  1. Regla 1: Mismo target → busca otro insight en el mismo target sin grupo.
  2. Regla 2: Misma subnet → busca otro insight en misma subnet sin grupo.
  3. Regla 3: Fingerprint → busca patrón existente por anomalía/host.

En cada regla, si encuentra un grupo existente:

def correlate_new_insight(insight):
    # Regla 1
    same_target = AIInsight.objects.filter(target=insight.target, status__in=RECENT_STATUSES).first()
    if same_target and same_target.incident_group:
        insight.incident_group = same_target.incident_group
        insight.save(update_fields=["incident_group"])
        reopen_group(same_target.incident_group)  # ← AQUÍ
        logger.info(f"Correlated {insight.case_id} → group '{same_target.incident_group.title}' (rule 1)")
        return same_target.incident_group
    
    # Regla 2
    same_subnet = ...
    if same_subnet and same_subnet.incident_group:
        insight.incident_group = same_subnet.incident_group
        insight.save(update_fields=["incident_group"])
        reopen_group(same_subnet.incident_group)  # ← AQUÍ
        logger.info(f"Correlated {insight.case_id} → group '{same_subnet.incident_group.title}' (rule 2)")
        return same_subnet.incident_group

Caso de uso real

Escenario: Switch S1 entra en bucle STP a las 03:00, se detecta.

  1. 03:15 → Insight A: “STP loop on S1”. Grupo “Switch-Storm-S1” creado.
  2. 04:30 → Reconoces y cierras el insight (ACK). Grupo se resuelve.
  3. 10:00 → Switch S1 vuelve a entrar en loop (problema no arreglado en realidad, falsa recuperación). Insight B detecta.
  4. 10:02 → Correlación: Insight B busca insights recientes en S1 → encuentra A (en grupo).
  5. Acción: Grupo “Switch-Storm-S1” se reabre. MTTR del primer episodio se captura; MTTR del segundo episodio nuevo empieza.

Sin esto, Insight B se perdería en el grupo ya cerrado y no sería accionable desde la UI.


Estados posibles

open ─→ (close_group_if_done) ─→ resolved
  ↑                                    │
  └────── (reopen_group) ────────────┘

Flujo normal:

  1. Grupo creado en open.
  2. Al cerrar todos los insights, pasa a resolved (con fecha).
  3. Si insight nuevo correlaciona, regresa a open (sin fecha).

Precondiciones y garantías

Precondiciones:

Garantías:


Interacción con close_group_if_done()

Estas dos funciones forman un ciclo de vida simétrico:

TransiciónFunciónCondición
open → resolvedclose_group_if_done()Todos los insights en estado terminal (ack/applied/expired).
resolved → openreopen_group()Nuevo insight correlaciona al grupo.

Invariante: Un grupo nunca salta open ↔ resolved sin razón. El cambio siempre tiene causa en los datos de insights.


Pruebas

Véase tests/api/test_itsm_close_cycle.py:


Impacto en UX


Véase también

Subir