Startup
There are two stages in rosia's coordinated startup: initialization and startup.
Initialization
The initialization stage is orchestrated by the Application.execute() method. It sets up all nodes before execution begins. No inter-node communication happens during this stage. The steps are:
-
Remote node setup: For each node, the executor calls
init_remote(), which sets up a ZeroMQ PULL endpoint for receiving messages and stores its endpoint string for other nodes to push to.init_remote()also runs_compute_upstream_topology(), which BFS-walks the upstream graph to collect every transitive upstream node and the minimum cumulative delay from each one toself. The same routine detects whetherselfis in a cycle (via a downstream BFS) and stores the result inself.in_cycle. -
Output transport initialization: Each node is updated with the endpoints of all downstream nodes. ZeroMQ PUSH sockets are created for each output port connection, so nodes can send messages to their downstream recipients.
-
Node instance initialization: The user's
__init__method is called on each node. Nodes load models, allocate resources, and set internal state. Nodes do not communicate during this step.
There is no separate STAT-propagation step. STAT is computed lazily during the event loop from the ENT entries that arrive in messages. A node's initial view of every transitive upstream's ENT defaults to never
(meaning "no information yet"), so its STAT is never until the first upstream message arrives.
Startup
After initialization completes, all nodes begin execution simultaneously:
-
Start logical time: The coordinator records the current physical time as the start time and sends it to all nodes via
execute(start_logical_time). -
start()call: If a node defines astart()method, it is called before the event loop begins. This is the first user-controlled function called during execution. Nodes can write to output ports instart(), andstart()may yield to schedule a future reaction. Logical time isTime(0)throughoutstart(). -
Initial broadcast: After
start()returns, the node callssend_messages()only if it actually has something to broadcast — either an output value written duringstart()or a reaction scheduled by ayield. Nodes with neither (typical pure relays) skip the initial send. Their downstreams' defaultENT[self] = neverkeeps STAT pinned until the node later receives an upstream message and naturally has something to report.Skipping the empty-startup broadcast prevents a relay from prematurely telling downstream "I have no scheduled work" before it has even drained its first upstream message. Without this, multi-input downstream receivers could race past pending events.