Skip to main content

read_node_statuses

Function read_node_statuses 

Source
pub fn read_node_statuses(paths: &RunPaths) -> Result<Vec<(NodeId, Status)>>
Expand description

The log-authoritative per-node status set for a run, replayed once from events.jsonl — the source-of-truth alternative to a nodes/*.json projection scan.

Returns every node a node.created event introduced, paired with the status the log replays for it, deduped and sorted by numeric suffix (NodeId order). Both the node set and each node’s status come from the log, so the result includes a node whose node.created was fsynced while its projection write was crash-interrupted (the node a nodes/*.json scan would silently drop) and reports a node terminal whenever the log says so even if its projection still reads live (the window crate::events documents the log leading the projections through).

This is what lets a supervisor’s run-status roll-up stay log-authoritative: terminalizing a run from the projection subset can miss a log-visible live node and roll the run up while it is still running, which a later rebuild_projections would then resurrect as live under a terminal run (violating “a run must not terminalize while a log-visible node is live” — issue rollup-status-log-authoritative). Feeding this into aggregate_terminal_status closes that window. It is the read half cancel_node’s in-lock self-roll-up already uses via the cancel ledger; both now share the NodeStatusAcc state machine so the supervisor tick and the cancel path can never diverge.

Reads through RunPaths::checked_events (a symlinked log is refused) and shares the crate’s streaming torn-tail policy: a crash-truncated final line is dropped, an interior unparseable line surfaces as Error::CorruptEventLog, and a missing log yields an empty set.

Cost. One streaming pass over the whole log — O(total events), not O(nodes). Memory stays bounded (each line is skimmed envelope + a few small status fields, never the full node.report payload — a run with hundreds of nodes and multi-KB reports is scanned without ever holding a report in memory), but the work is linear in the event count, not the node count. A caller that polls this every tick (the supervisor roll-up) re-reads from byte 0 each time; at the tool’s scale (tens of nodes, hundreds of events, multi-second ticks) that is negligible, but an incremental fold that resumes from the last consumed offset would be the optimization if a run’s log ever grows large enough to matter.

§Errors

I/O errors reading the log, a rejected symlinked path, or an interior corrupt event line.