Ir al contenido

Rule chains

Mientras que el rules engine maneja una lógica simple de condición → acción por punto, las rule chains son un grafo de nodos que enrutan, transforman, enriquecen y actúan sobre los mensajes a medida que fluyen. Una chain es el lugar para construir pipelines de múltiples pasos: filtrar, buscar un activo relacionado, condicionar según la finalidad en blockchain, crear una alarm, y enviar a un sistema externo — todo con ramificación explícita, reintentos y una dead-letter queue.

Las rule chains están acotadas al tenant y se almacenan en el namespace de Aerospike rules, set chains (con clave {tenant_id}:{chain_id}), con versiones desplegadas inmutables en rules/chain_versions (con clave {tenant_id}:{chain_id}:{version}).

Una versión de rule chain es un grafo dirigido: nodos conectados por links, con un root_node_id designado donde entran los mensajes. Un registro de versión contiene chain_id, version, name, status, nodes, links, root_node_id, created_by, deployed_at, config_hash y schema_version.

flowchart TD
  input["input:<br/>telemetry"] --> filter{"filter:<br/>CEL<br/>data.temperature > 80"}
  filter -->|true| finality["blockchain:<br/>require final proof"]
  filter -->|false| done([drop])
  finality -->|final| enrich["enrichment:<br/>get related asset"]
  finality -->|not final| wait([route to not_final])
  enrich --> alarm["action:<br/>create alarm"]
  alarm --> connector["connector:<br/>HTTP POST<br/>(SSRF-checked)"]
  connector -->|2xx| ok([success])
  connector -->|retries exhausted| dlq[("DLQ")]

El runtime admite estas categorías de nodo integradas:

CategoríaNodos
inputtelemetry, evento de dispositivo, evento de alarm, respuesta RPC, schedule
filterfiltro CEL, switch de tipo de mensaje, switch de tipo de originator, filtro de relation
transformtransformación por script, renombrar / copiar / eliminar claves, JSON path, dividir array
enrichmentatributos de dispositivo, atributos de cliente, datos de entity relacionada, última telemetry
actioncrear alarm, hacer clear de alarm, guardar telemetry, actualizar atributos, enviar RPC, programar notificación
connectorHTTP, MQTT, Kafka, RabbitMQ, Google Pub/Sub, AWS SNS/SQS/Lambda, Redpanda, email
flowcheckpoint, delay, deduplication, retry, output, input de rule-chain
blockchainrequire final proof, attach proof status, export proof bundle

Algunos que vale la pena destacar para los operadores:

  • Enriquecimiento desde entidades relacionadas. Si el dispositivo D1 está relacionado con el activo A1 por located_at, un nodo “get related asset” adjunta asset_id=A1 y los campos de activo configurados a los metadatos del mensaje — dejando que los nodos downstream ramifiquen sobre el contexto del activo. Consulta el entity model.
  • Filtro de finalidad en blockchain. Un nodo require_final_proof inspecciona el estado de prueba del mensaje. Si un punto está solo anchored (aún no final), el nodo lo retrasa o lo enruta a una relation not_final según su configuración; una vez que el punto alcanza final, el mensaje continúa. Así es como una chain puede garantizar que solo actúa sobre datos finalizados en blockchain.
  • Crear alarm. Enruta hacia el subsistema de alarms de primera clase — consulta Alarms y notificaciones.

La edición ocurre sobre un draft; desplegar produce una versión inmutable.

  1. Crear / editar un draft. Crear una chain inicia la versión 1 con status="draft" y publica rulechain.created.T1.{chain_id}.

  2. Validar antes de desplegar. El deploy ejecuta primero la validación de grafo (ver más abajo).

  3. Deploy. En caso de éxito, la nueva versión se convierte en active; la versión previamente activa se conserva para rollback. Se publica un evento rulechain.deployed.T1.{chain_id}.v{n}.

Como las versiones desplegadas son inmutables, siempre sabes exactamente qué grafo procesó un mensaje dado — la versión se registra en los registros de DLQ y en los trazos de debug.

Una chain no se puede desplegar a menos que su grafo sea estructuralmente sólido. La validación rechaza, con INVALID_ARGUMENT y errores específicos, problemas como:

  • Un link que apunta a un nodo faltante (p. ej. un link a N9 que no existe) — el error identifica el nodo faltante.
  • Ciclos en el grafo y nodos inalcanzables.

Si la validación falla, la versión previamente desplegada permanece activa — un draft defectuoso nunca tumba una chain en ejecución.

Cada versión desplegada se conserva, así que hacer rollback es simplemente reactivar una versión anterior. Hacer rollback de la chain C1 desde la versión activa 4 a la versión 3 hace que la versión 3 vuelva a estar activa y publica rulechain.rolled_back.T1.C1.v3.

Los nodos connector se conectan a sistemas externos (endpoints HTTP, Kafka, MQTT, colas en la nube, email). DEBEN admitir reintentos acotados, timeouts, autenticación, referencias a secretos, y red saliente segura frente a SSRF.

  • Referencias a secretos. Las credenciales se referencian, no se incrustan — la configuración del connector contiene una referencia que se resuelve en tiempo de ejecución, de modo que los secretos nunca se almacenan en el grafo de la chain ni se incluyen en los bundles de export.
  • Política SSRF. Los targets salientes se validan. Un connector apuntado a una dirección interna o de metadatos — por ejemplo http://169.254.169.254/latest/meta-data — se rechaza en tiempo de validación con INVALID_ARGUMENT, y un audit event rulechain.connector.rejected registra reason="ssrf_blocked".

En caso de éxito, un connector HTTP enruta el mensaje a su relation success ante una respuesta 2xx. En caso de fallo, reintenta dentro de su política acotada; si un connector (p. ej. Kafka) agota sus reintentos, el mensaje va a la dead-letter queue y una métrica de fallo de nodo se incrementa con el tipo de nodo.

Los mensajes fallidos aterrizan en una DLQ acotada al tenant con suficiente contexto para inspeccionarlos, hacerles replay o descartarlos. Un registro de DLQ contiene dlq_id, tenant_id, chain_id, chain_version, node_id, message_payload, metadata, failure_reason, retry_count, first_failed_at, last_failed_at y status.

  • A la entrada. Un fallo no reintentable (p. ej. un error de validación en el nodo N1) crea un registro de DLQ y publica rulechain.dlq.created.T1.{dlq_id}.
  • Replay. Hacer replay de un registro abierto reejecuta el mensaje — normalmente contra la última versión desplegada, que es el sentido del replay después de haber corregido y redesplegado una chain. El status del registro pasa a replayed y se escribe un audit event rulechain.dlq.replayed.
  • Descarte. Los registros que no pretendes reprocesar se pueden descartar.

Para inspeccionar una chain sin almacenar permanentemente los payloads completos, inicia una sesión de debug por un tiempo acotado.

  • Iniciar una sesión de debug (p. ej. 10 minutos en la chain C1) hace que se emitan registros de trazo por nodo a rulechain.debug.T1.C1. La UI muestra, por nodo, su status, latencia, metadatos de entrada, metadatos de salida y detalles de error.
  • Cuando la sesión expira, la emisión de trazos se detiene y la sobrecarga del runtime vuelve a la normalidad — el debugging es opt-in y con tiempo limitado, no un coste siempre presente.

Los payloads completos no se persisten a menos que configures explícitamente la sesión para hacerlo.

La UI ofrece un editor de grafos con una paleta de nodos, paneles de configuración por nodo, validación de grafo, deploy, rollback, la vista de trazo de debug y el replay de DLQ. Hacer clic en Deploy ejecuta la misma validación descrita arriba y, en caso de éxito, publica una nueva versión inmutable cuyos metadatos se muestran en el lienzo.