Volver a la wiki

ADR: log_action() best-effort (nunca rompe request)

Decisión

log_action() es best-effort — cualquier fallo en escribir el log de auditoría nunca rompe la request del usuario. Las excepciones se capturan, se loguean internamente, y se ignoran.

Status: Adoptado (2026-06-07, PR #71)

Contexto

Problema

Las mutaciones en ITSM/alertas/wireless/UPS son críticas y deben completarse incluso si la capa de auditoría falla:

  1. Un operador elimina una alerta falsa-positiva → la alerta debe desaparecer ahora mismo
  2. Si SystemLog está lento o la BD saturada, no podemos dejar la alerta activa
  3. Un fallo de auditoría es mejor que un fallo de negocio

Alternativas consideradas

  1. Síncrono + fail-fast: log_action() lanza si hay error

    • ❌ Riesgo: Un problema de BD bloquea todas las mutaciones
    • ❌ UX: Usuario ve error en request de negocio puro (ej: “delete failed — logging error”)
  2. Asincrónico (Celery): Encolamos el log en background

    • ✅ No bloquea request
    • ⚠️ Complejidad: Celery broker + workers + retry logic
    • ⚠️ Pérdida eventual: Si worker falla persistentemente, log se pierde silenciosamente
    • ❌ Overhead: Para ~20 mutaciones/min, no justifica Celery
  3. Best-effort (elegido):

    • ✅ Síncrono pero aislado en try-except
    • ✅ Request nunca se afecta
    • ✅ Fallos registrados en logger para debugging
    • ✅ Simplicidad: una función, sin deps externas

Decisión

Best-effort: log_action() intenta escribir SystemLog, pero si falla por cualquier razón, la excepción se captura y se loguea a logging.getLogger("core"). La función retorna None siempre, nunca lanza.

def log_action(request, category: str, action: str, details: str = "", level: str = "INFO") -> None:
    try:
        # ... resolve org, user, create SystemLog ...
    except Exception:
        logger.exception("log_action failed (category=%s action=%s)", category, action)
        # NCA: nunca re-raise

Implicaciones

Positivas

Negativas (aceptadas)

Monitoreo recomendado

ALERT log_action_failure_rate > 0.1%
  IF increase(log_action_failures_total[5m]) / increase(mutations_total[5m]) > 0.001

Alternativa futura: Celery + queue fallback

Si la tasa de pérdida de logs crece o compliance requiere 100% trazabilidad:

  1. Cambiar a log_action_async(request, ...) con Celery
  2. Implementar fallback local: encolar en SQLite si broker no disponible
  3. Worker consume localmente cuando broker recupera

Costo: +2-3 días de dev + mantenimiento de broker.

Referencias

Véase también

Subir