Ir al contenido

Rules engine

El rules engine evalúa una expresión CEL contra cada punto de telemetry validado y despacha acciones cuando coincide. Es la capa reactiva ligera, por punto: lógica simple de condición-a-acción que se ejecuta en menos de 5ms. Para el procesamiento de grafos de múltiples pasos — enriquecimiento, ramificación, connectors, manejo de dead-letter — consulta Rule chains.

Una regla es una condición (una expresión CEL), un grupo de dispositivos al que se aplica, y una o más acciones a disparar cuando la condición es verdadera.

El engine consume el mismo flujo de telemetry enriquecido y validado que tus dispositivos producen al enviar telemetry, y evalúa las reglas coincidentes contra cada punto. La evaluación debe completarse en 5ms por punto.

flowchart TD
  point([Validated point<br/>telemetry.validated.T1]) --> scope{Device in the<br/>rule's group?}
  scope -->|no| skip([Rule not evaluated])
  scope -->|yes| eval{CEL condition true?}
  eval -->|no| none([No action])
  eval -->|yes| act["Dispatch actions"]
  act --> event["Publish rule.triggered.T1.{rule}"]
  act --> metric["Increment rules_triggered_total"]

Las condiciones se escriben en CEL (Common Expression Language). Solo las variables de abajo están en el ámbito; referenciar cualquier otra cosa es un error en tiempo de compilación, de modo que una regla rota nunca se puede guardar.

VariableTipoDescripción
datamap(string, double)Valores numéricos de telemetry, p. ej. data.temperature
data_strmap(string, string)Valores de cadena de telemetry, p. ej. data_str.firmware_status
device.idstringID de dispositivo
device.namestringNombre para mostrar
device.groupslist(string)Pertenencia a grupos
device.tagsmap(string, string)Pares clave-valor de tags
device.firmwarestringVersión de firmware
device.statusstringonline / offline
device.last_seenintMarca de tiempo Unix (segundos) de la última telemetry
timestampintMarca de tiempo Unix (segundos) del punto actual
tenant_idstringTenant ID

Cuando se crea o actualiza una regla, la expresión CEL se compila y valida antes de almacenarse. Se detectan dos clases de error por adelantado:

  • Errores de sintaxis. Una expresión malformada como data.temperature >> se rechaza con INVALID_ARGUMENT y un error de parseo legible para humanos.
  • Referencias no declaradas. Usar una variable que no está en el ámbito — p. ej. data.temperature > threshold — falla con “undeclared reference to ‘threshold’” e INVALID_ARGUMENT.

Por eso las reglas son rápidas en tiempo de ejecución: para cuando una regla se almacena, ya es un artefacto validado y compilado, no una cadena que parsear por cada punto.

Cada regla apunta a un grupo de dispositivos. Un punto solo se evalúa contra las reglas cuyo grupo objetivo contiene el dispositivo de origen. Una regla para el grupo furnace nunca se evalúa para un dispositivo del grupo hvac — el engine la omite por completo en lugar de evaluarla y luego descartarla. Esto mantiene el trabajo por punto proporcional a las reglas que realmente aplican.

Alertar cuando cualquier dispositivo de furnace supere los 80 °C:

data.temperature > 80

Grupo objetivo: furnace. Acción: webhook a tu endpoint de alertas.

Una regla dispara una o más de estas acciones cuando su condición es verdadera:

AcciónComportamiento
WebhookHTTP POST que transporta el punto de telemetry más los metadatos de la regla. Se reintenta 3 veces con exponential backoff; en el fallo final se registra con contexto de trazo y rule_action_failures_total{type="webhook"} se incrementa.
Comando MQTTPublica un payload de comando en el topic EMQX devices/{device_id}/commands — p. ej. {"set_fan": "high"}.
EmailEnvía una notificación por SMTP.
Evento RedpandaPublica un evento en un subject de Redpanda para consumidores downstream.

Cada vez que una regla se dispara, además de sus acciones, el engine:

  • Publica un evento en rule.triggered.{tenant_id}.{rule_id} que transporta rule_id, device_id y los valores del disparo. Esto es lo que impulsa los feeds de disparos de regla en vivo y el historial de disparos por regla en la UI.
  • Incrementa rules_triggered_total{tenant="T1",rule="R1"}.

Si una regla no coincide, no se despacha ninguna acción y no se publica ningún evento.

Las reglas compiladas se cachean en el namespace de Aerospike rules, set compiled, con clave {tenant_id}:{rule_id}, con un TTL de 600 segundos (10 minutos). La evaluación lee la forma compilada lista para ejecutar desde esta caché en lugar de recompilar por cada punto. Una consecuencia práctica: después de editar o deshabilitar una regla, el cambio surte pleno efecto dentro de la ventana del TTL de la caché. Deshabilitar una regla establece su flag enabled en false para que las evaluaciones posteriores la omitan.

Cuando creas o actualizas una regla, el engine comprueba si hay reglas potencialmente en conflicto — por ejemplo, dos reglas en el mismo grupo de dispositivos con condiciones solapadas. Los conflictos son informativos, no bloqueantes: la regla se guarda y la respuesta incluye un array warnings que indica el solapamiento.

Cuándo recurrir a las rule chains en su lugar

Sección titulada «Cuándo recurrir a las rule chains en su lugar»

Usa el rules engine para lógica simple y sin estado de condición → acción. Recurre a las rule chains cuando necesites enriquecer un mensaje con datos de activo o de entity relacionada, ramificar según múltiples condiciones, condicionar según la finalidad en blockchain, abanicar hacia connectors externos con reintentos y una dead-letter queue, o crear y gestionar alarms como entidades de primera clase.