Ir al contenido

Alarms y notificaciones

CORE-M modela las alarms como entidades de primera clase, acotadas al tenant — no como simples líneas de log. Una alarm tiene un ciclo de vida, un propietario, un historial de comentarios y cambios de estado, e impulsa notificaciones. Esta página cubre la entity alarm y su ciclo de vida, y luego el sistema de notificaciones que enruta las alarms hacia personas y sistemas.

Las alarms son creadas por rule chains, cambios de estado de dispositivos, adaptadores de protocolo o monitores del sistema, y se almacenan en el namespace de Aerospike rules, set alarms, con clave {tenant_id}:{alarm_id}.

Un registro de alarm contiene alarm_id, tenant_id, originator_type, originator_id, type, severity, status, assignee_user_id, start_ts, end_ts, acknowledged_at, cleared_at, details_json, latest_event_hash, created_at, updated_at y version. Los índices secundarios permiten filtrar por tenant_id, originator_id, severity, status, type y las marcas de tiempo — lo que alimenta los filtros del centro de alarms.

Cuando se dispara un nodo create-alarm (por ejemplo, el dispositivo D1 reporta una temperatura de 95), se crea una alarm con status="ActiveUnack", la severity configurada, originator_id="D1" y el type definido por la regla. La plataforma entonces:

  • Publica alarm.created.T1.{alarm_id}.
  • Envía alarm_update a los clientes WebSocket suscritos a las alarms del tenant.
  • Actualiza corem_alarms_total{severity,status}.

Una alarm tiene dos dimensiones ortogonales: active vs cleared (la condición) y unacknowledged vs acknowledged (atención del operador). Los cuatro valores de status las combinan:

StatusCondiciónOperador
ActiveUnackAún activaSin acknowledge todavía
ActiveAckAún activaCon acknowledge
ClearedUnackClearedSin acknowledge todavía
ClearedAckClearedCon acknowledge

Conceptualmente, este es el flujo familiar triggered → acknowledged → cleared, con el matiz de que una alarm cleared puede reabrirse si la condición vuelve a ocurrir.

stateDiagram-v2
  [*] --> ActiveUnack: alarm created
  ActiveUnack --> ActiveAck: acknowledge
  ActiveUnack --> ClearedUnack: clear
  ActiveAck --> ClearedAck: clear
  ClearedUnack --> ClearedAck: acknowledge
  ClearedAck --> ActiveUnack: condition recurs (reopen)
  ClearedUnack --> ActiveUnack: condition recurs (reopen)
  1. Acknowledge. Un usuario con el permiso alarms hace acknowledge de la alarm, opcionalmente con un comentario (“Investigando”). El status pasa a ActiveAck; se establecen acknowledged_by y acknowledged_at; el comentario se añade al historial; se escribe el audit event alarm.acknowledged.

  2. Clear. Hacer clear con una resolución (“Ventilador reemplazado”) mueve el status a ClearedAck, registra cleared_by, cleared_at y resolution, y publica alarm.cleared.T1.{alarm_id}.

  3. Reopen. Si la misma condición de alarm se vuelve a disparar dentro de la ventana de deduplication, la alarm se reabre a ActiveUnack, reopened_count se incrementa, y los metadatos del clear anterior permanecen en el historial.

Deduplication y severity en un nuevo disparo

Sección titulada «Deduplication y severity en un nuevo disparo»

Las alarms se deduplican por originator y type. Si ya hay una alarm activa para (tenant, device, type), un nuevo disparo actualiza la alarm existente en lugar de generar una nueva: latest_event_hash y updated_at cambian, repeat_count se incrementa, y se publica alarm.updated.T1.{alarm_id}. Esto evita que un sensor ruidoso inunde el centro de alarms con duplicados.

La severity es una de Critical, Major, Minor, Warning o Indeterminate. En un nuevo disparo, la severity de la alarm se sobrescribe incondicionalmente con la severity del nuevo disparo — no hay contador de escalado, y la severity puede bajar además de subir. Si una alarm Major se vuelve a disparar como Minor, la alarm pasa a Minor; si se vuelve a disparar como Critical, pasa a Critical. Las reglas de notificación se reevalúan entonces contra la nueva severity.

Cada transición del ciclo de vida — acknowledge, clear, reopen, comentario, asignación — queda registrada en el historial de la alarm, y las transiciones notables emiten audit events. Esto da a los operadores un registro completo, de solo adición (append-only), de quién hizo qué y cuándo.

Las transiciones del ciclo de vida usan comprobaciones de generation de Aerospike (compare-and-swap) para evitar actualizaciones perdidas. Si dos operadores cargan la alarm A1 en la versión 4 y ambos intentan hacer acknowledge:

  • La primera escritura tiene éxito.
  • La segunda, que aún sostiene la versión obsoleta 4, se rechaza con ABORTED / HTTP 409, y la respuesta devuelve la versión y el status actuales para que la UI pueda refrescarse.

El mismo CAS por registro aplica a las acciones masivas: hacer acknowledge de 25 alarms a la vez aplica CAS por cada alarm e informa los fallos por alarm_id, de modo que la UI puede mostrar éxito parcial cuando algunas alarms cambiaron de forma concurrente.

Las alarms impulsan notificaciones: mensajes entregados a personas o sistemas. Los notification targets, las plantillas y las reglas están acotados al tenant y se almacenan en el namespace de Aerospike rules, set notifications, con clave {tenant_id}:{notification_id}.

Tipo de targetNotas
smtpEntrega de email por SMTP
slackEstilo incoming-webhook de Slack
teamsIncoming webhook de Microsoft Teams

Las plantillas renderizan el cuerpo del mensaje con sustitución de variables a partir de campos de la alarm y del dispositivo. Las plantillas están versionadas: editar una plantilla versiona el contenido anterior y escribe un audit event con template_id, old_version, new_version y actor_user_id.

Una regla de notificación lo une todo: un matcher (p. ej. severity="Critical" y status="ActiveUnack"), uno o más targets, una plantilla, además de quiet hours, escalation, suppression y una ventana de deduplication. Cuando una alarm coincide con una regla, se crea un registro de notificación con status="scheduled", se publica notification.scheduled.T1.{notification_id}, y el worker renderiza la plantilla.

flowchart TD
  match([Alarm matches rule]) --> sched["status = scheduled"]
  sched --> send{Deliver to target}
  send -->|accepted| delivered["status = delivered<br/>record delivered_at,<br/>provider_message_id"]
  send -->|error| retry{Retries left?}
  retry -->|yes| backoff["Exponential backoff,<br/>retry per rule policy"]
  backoff --> send
  retry -->|no| failed["status = failed<br/>store failure_reason"]

En caso de éxito, la notificación pasa a delivered, registrando delivered_at y el provider_message_id, y publicando notification.delivered.T1.{notification_id}. En caso de fallo, el worker reintenta con exponential backoff según la política de la regla; tras el máximo de intentos, el status pasa a failed, failure_reason almacena el error final del proveedor, y corem_notification_delivery_failures_total{target_type} se incrementa.

Las reglas de notificación admiten varios controles para mantener las alertas útiles en lugar de ruidosas:

  • Quiet hours. Aplazan las notificaciones no críticas durante una ventana (p. ej. 22:00–07:00 en la hora local del tenant). Una alarm Warning a las 23:00 produce una notificación deferred que se retiene hasta las 07:00, sin ninguna llamada al proveedor mientras tanto.
  • Bypass de críticas. Una regla puede permitir que las alarms Critical omitan las quiet hours — una alarm crítica durante la ventana silenciosa se programa de inmediato.
  • Escalation. Si una alarm permanece en ActiveUnack más allá de un umbral (p. ej. 15 minutos), el planificador de escalation programa la notificación del siguiente nivel (p. ej. nivel 2 → “oncall-manager”) y registra escalation_level en el historial de la alarm.
  • Ventanas de suppression y dedup. Las ventanas de suppression y deduplication por target evitan que disparos repetidos generen notificaciones repetidas.

Donde la política del tenant lo permite, los usuarios pueden establecer preferencias personales de notificación — por ejemplo, optar por no recibir email mientras mantienen las notificaciones in-app — y el cambio se audita (notification.preference.updated). Cada cambio de regla de notificación y cada cambio de estado de entrega produce un audit event, de modo que toda la configuración de alertas y sus resultados de entrega son trazables.