Message Broker API
The ai_nn_controller message broker routes measurements from nodes to applications and commands from applications to nodes.
UnifiedMeasurementBroker
- class node_msg_broker.UnifiedMeasurementBroker(context, recv_port=5555, send_port=5554)
Broker that receives measurements from nodes and publishes to applications.
Pattern:
Nodes PUSH → Broker PULL → Broker PUB → Apps SUB- Parameters:
context – ZMQ context
recv_port – Port to receive measurements (PULL socket)
send_port – Port to publish measurements (PUB socket)
Methods:
- run()
Start the forwarding loop. Receives from any node and publishes to all subscribers.
CommandBroker
- class node_msg_broker.CommandBroker(context, recv_port=5556, send_port=5557)
Broker for command messages from applications to nodes.
Pattern:
Apps PUSH → Broker PULL → Broker PUB → Nodes SUB- Parameters:
context – ZMQ context
recv_port – Port to receive commands (PULL socket)
send_port – Port to publish commands (PUB socket)
Methods:
- run()
Start the command forwarding loop.
Port Configuration
Port |
Socket |
Direction |
Purpose |
|---|---|---|---|
5554 |
PUB |
→ Apps |
Measurement publication |
5555 |
PULL |
← Nodes |
Measurement collection |
5556 |
PULL |
← Apps |
Command collection |
5557 |
PUB |
→ Nodes |
Command publication |
Message Format
All messages use the format:
"{topic};{MessageEnvelope_JSON}"
Where:
topic= node_id as string — used by ZMQ PUB/SUB for routingMessageEnvelope_JSON= JSON-serialisedMessageEnvelopeobject
The MessageEnvelope (defined in ai_nn_controller/protocol/envelope.py) is the
authoritative wire schema (urn:ai-nnc:envelope:1):
{
"schema": "urn:ai-nnc:envelope:1",
"version": "1.0",
"message_type": "measurement",
"source": "3",
"target": "controller",
"correlation_id": "<uuid4>",
"lineage_id": "<uuid4>",
"idempotency_key": "<uuid4>",
"ts": 1741785600.123,
"payload": {"amp1_target_gain": 20.5, "amp1_gain_tilt": 1.2}
}
The payload field carries measurement data (for measurement messages) or command
parameters (for command messages). The idempotency_key on command messages is used
by nodes to deduplicate retried or duplicated commands.
Topic-Based Routing
ZMQ PUB/SUB uses topic-based filtering:
Publishers send:
"{topic};{payload}"Subscribers subscribe to topics:
socket.setsockopt(zmq.SUBSCRIBE, b"3")Only messages with matching topic prefix are delivered
This allows:
Apps to subscribe only to nodes they care about
Nodes to receive only commands addressed to them
Usage
The broker is typically run as a standalone service:
import zmq
from node_msg_broker import UnifiedMeasurementBroker, CommandBroker
context = zmq.Context()
# Create brokers
meas_broker = UnifiedMeasurementBroker(context, recv_port=5555, send_port=5554)
cmd_broker = CommandBroker(context, recv_port=5556, send_port=5557)
# Start in threads
import threading
threading.Thread(target=meas_broker.run, daemon=True).start()
threading.Thread(target=cmd_broker.run, daemon=True).start()
# Keep main thread alive
while True:
time.sleep(1)
Or using the provided main function:
python node_msg_broker.py
Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ MESSAGE BROKER │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Measurement Flow │ │
│ │ │ │
│ │ Node 3 ──┐ │ │
│ │ Node 4 ──┼──► PULL:5555 ──► PUB:5554 ──┬──► App A │ │
│ │ Node 8 ──┘ └──► App B │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Command Flow │ │
│ │ │ │
│ │ App A ──┐ │ │
│ │ App B ──┼──► PULL:5556 ──► PUB:5557 ──┬──► Node 3 │ │
│ │ │ ├──► Node 4 │ │
│ │ └ └──► Node 8 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Scaling Considerations
The current broker design:
Handles multiple nodes and apps
Does not require configuration for specific nodes
Nodes self-register by simply connecting
For high-throughput scenarios:
Consider running multiple broker instances
Use ZMQ ROUTER/DEALER for load balancing
Implement message batching