Node Discovery & Monitoring

These types are for building custom monitoring and discovery tools. Most users don't need them — the built-in Monitor handles this automatically.


NodePresence

Node presence files written to shared memory for cross-process discovery. The scheduler creates these automatically at startup; monitoring tools read them. Paths are managed by horus_sys and vary by platform.

use horus::prelude::*; // NodePresence is available via the prelude

// Discover all running HORUS nodes on this machine
let nodes = NodePresence::read_all();
for node in &nodes {
    println!("{}: pid={}, rate={:?}Hz, health={:?}, ticks={}, errors={}",
        node.name(), node.pid(), node.rate_hz(),
        node.health_status(), node.tick_count(), node.error_count());
}

// Read a specific node
if let Some(motor) = NodePresence::read("motor_ctrl") {
    println!("Publishers: {:?}", motor.publishers());
    println!("Services: {:?}", motor.services());
}
MethodReturnsDescription
name()&strNode name
pid()u32Process ID (verified for liveness)
scheduler()Option<&str>Scheduler name
publishers()&[TopicMetadata]Topics this node publishes
subscribers()&[TopicMetadata]Topics this node subscribes to
rate_hz()Option<f64>Configured tick rate
health_status()Option<&str>Healthy / Warning / Error / Critical
tick_count()u64Total ticks since start
error_count()u32Total errors since start
services()&[String]Provided services
actions()&[String]Provided actions

Static methods: read(name) → Option<Self>, read_all() → Vec<Self>


NodeAnnouncement

Real-time lifecycle events broadcast on the horus.ctl.{scheduler} topic. Unlike presence files (polled), announcements are push-based — you get notified the moment a node starts or stops.

// discovery module removed — node lifecycle managed via SchedulerRegistry + control topic
use horus::prelude::*;

let discovery: Topic<NodeAnnouncement> = Topic::new(DISCOVERY_TOPIC).unwrap();
if let Some(ann) = discovery.recv() {
    match ann.event {
        NodeEvent::Started => {
            println!("{} started (pid={})", ann.name, ann.pid);
            println!("  publishes: {:?}", ann.publishers);
            println!("  subscribes: {:?}", ann.subscribers);
        }
        NodeEvent::Stopped => println!("{} stopped", ann.name),
    }
}
FieldTypeDescription
nameStringNode name
pidu32Process ID
eventNodeEventStarted or Stopped
publishersVec<String>Published topic names
subscribersVec<String>Subscribed topic names
timestamp_msu64Event timestamp

See Also