Scheduler API

The Scheduler orchestrates node execution with composable builder configuration.

use horus::prelude::*;

Scheduler

Constructor

let mut scheduler = Scheduler::new();

Creates a scheduler with auto-detected platform capabilities (RT support, CPU topology, memory locking).

Builder Methods

All builder methods return Self for chaining:

let mut scheduler = Scheduler::new()
    .tick_rate(1000_u64.hz())
    .prefer_rt()
    .watchdog(500_u64.ms())
    .blackbox(64)
    .max_deadline_misses(3)
    .verbose(false)
    .with_recording();
MethodDefaultDescription
.tick_rate(freq)100 HzGlobal scheduler tick rate
.prefer_rt()Try RT features (mlockall, SCHED_FIFO), warn on failure
.require_rt()Enable RT features, panic if unavailable
.watchdog(Duration)disabledDetect frozen nodes (auto-creates safety monitor)
.blackbox(size_mb)disabledFlight recorder for crash forensics
.max_deadline_misses(n)100Emergency stop threshold
.verbose(bool)trueEnable/disable non-emergency logging
.with_recording()disabledEnable session record/replay

Node Registration

scheduler.add(my_node)         // Returns NodeBuilder for fluent configuration
    .order(10)
    .rate(500_u64.hz())
    .build()?;
MethodReturnsDescription
.add(node)NodeBuilderRegister a node and configure it via fluent builder

Execution Control

MethodReturnsDescription
.run()HorusResult<()>Main loop — runs until Ctrl+C or .stop()
.run_for(duration)HorusResult<()>Run for specific duration, then shut down
.tick_once()HorusResult<()>Execute exactly one tick cycle (no loop, no sleep)
.tick_once_nodes(&[names])HorusResult<()>One tick for specific nodes only
.stop()()Signal graceful shutdown
.is_running()boolCheck if scheduler is actively ticking

Monitoring

MethodReturnsDescription
.metrics()Vec<NodeMetrics>Performance metrics for all nodes
.node_list()Vec<String>Names of all registered nodes
.status()StringFormatted status report

Example

use horus::prelude::*;

fn main() -> Result<()> {
    let mut scheduler = Scheduler::new()
        .tick_rate(1000_u64.hz())
        .prefer_rt()
        .watchdog(500_u64.ms());

    scheduler.add(SensorNode::new())
        .order(0)
        .rate(500_u64.hz())
        .build()?;

    scheduler.add(PlannerNode::new())
        .order(50)
        .compute()
        .build()?;

    scheduler.add(ControlNode::new())
        .order(10)
        .rate(1000_u64.hz())
        .on_miss(Miss::SafeMode)
        .build()?;

    scheduler.run()?;
    Ok(())
}

NodeBuilder

Returned by scheduler.add(node). Configure execution class, timing, ordering, and failure handling with method chaining.

Timing & Ordering

MethodDescription
.order(n)Execution priority within a tick (lower runs first)
.rate(Frequency)Node-specific tick rate — auto-derives budget (80%) and deadline (95%), auto-marks as RT
.budget(Duration)Explicit CPU time budget per tick
.deadline(Duration)Explicit deadline per tick
.on_miss(Miss)Deadline miss policy: Warn, Skip, SafeMode, Stop

Execution Class

MethodClassDescription
.compute()ComputeOffloaded to worker thread pool (planning, SLAM, ML)
.on(topic)EventWakes only when the named topic has new data
.async_io()AsyncIoRuns on async executor (network, disk, cloud)
(none)BestEffortDefault — ticks every scheduler cycle
.rate(freq)RT (auto)Auto-promoted when rate is set on a BestEffort node

Failure & Finalization

MethodDescription
.failure_policy(policy)Per-node failure handling (Fatal, Restart, Skip, Ignore)
.build()Finalize and register — returns HorusResult<&mut Scheduler>

Order Guidelines

RangeUse
0-9Critical real-time (motor control, safety)
10-49High priority (sensors, fast loops)
50-99Normal (processing, planning)
100-199Low (logging, diagnostics)
200+Background (telemetry)

Miss Enum

VariantBehaviorUse Case
Miss::WarnLog warning, continueSoft real-time (logging, UI)
Miss::SkipSkip this tickFirm real-time (video encoding)
Miss::SafeModeCall enter_safe_state()Motor controllers, safety nodes
Miss::StopStop entire schedulerHard real-time safety-critical

Default is Miss::Warn.


NodeMetrics

Returned by scheduler.metrics(). Read-only performance data for each node.

MethodReturnsDescription
.name()&strNode name
.order()u32Execution order
.total_ticks()u64Total tick count
.successful_ticks()u64Ticks without errors
.avg_tick_duration_ms()f64Mean tick duration
.max_tick_duration_ms()f64Worst-case tick duration
.min_tick_duration_ms()f64Best-case tick duration
.last_tick_duration_ms()f64Most recent tick duration
.messages_sent()u64Total messages published
.messages_received()u64Total messages consumed
.errors_count()u64Error count
.warnings_count()u64Warning count
.uptime_seconds()f64Node uptime

Performance Monitoring Example

// After running for a while, check node health
for metric in scheduler.metrics() {
    if metric.max_tick_duration_ms() > 1.0 {
        hlog!(warn, "Node '{}' worst case: {:.2}ms (avg: {:.2}ms)",
            metric.name(),
            metric.max_tick_duration_ms(),
            metric.avg_tick_duration_ms(),
        );
    }
}

See Also