Module runtime

Module runtime 

Source
Expand description

CP runtime: MPSC reducer loop + applier + workers (RFC-0006 §7.2).

§Architecture

  manifest_poll ─┐
  event_ingest  ─┼──▶  mpsc::Sender<ReducerInput>  ───▶  reducer task ───▶ applier
  heartbeat_rx  ─┤                                          │
  dispatch lp   ─┘                                          ▼
                                                      (step + plan_next)

Invariants (do not violate without an RFC amendment):

  1. One MPSC, one mutator. The reducer task is the only thing that calls nixfleet_state_machine::step or nixfleet_reconciler::planner::plan_next. Workers emit ReducerInput values; the applier executes the resulting effects. A second writer “for performance” is the defect class that the v0.2 fold is folding away — don’t reintroduce it.

  2. CP mirror runs the same step() as the agent. Identical transitions for Local* and Remote* event pairs by construction (RFC-0006 §2 principle 4). No “leaner” CP-side reimplementation.

  3. Shutdown via oneshot drop. The reducer task owns a vector of [tokio::sync::oneshot::Sender<()>]; each worker holds the matching ShutdownToken (wrapping a Receiver). Reducer exit drops every sender, every worker’s select! shutdown arm fires, workers exit cleanly. No leaks if a worker hangs on its own — the JoinHandle drain in server::mod aborts past the deadline.

  4. Bounded channels. The input MPSC and any internal applier queues have explicit bounded capacities with a sizing rationale in a comment — never unbounded, never “let’s start at 4096 and see.”

Re-exports§

pub use event_log_writer::EVENT_LOG_CHANNEL_CAPACITY;
pub use event_log_writer::EventLogTx;

Modules§

applier
Imperative shell for the pure planner + reducer (RFC-0006 §7.2).
event_log_writer
Event-log writer task: dedicated consumer of EventLogEntry values the reducer-task applier emits, persisting them to SQLite outside the reducer’s critical section.
reducer 🔒
Reducer task body: the single mutator of CP-mirror state.
workers
Workers — the I/O-bearing edges around the pure reducer.

Structs§

HeartbeatReply
Heartbeat reply: drift detected ⇒ replay_from is Some(last_known_seq); agent should re-POST events from that seq onward (RFC-0005 §4.3). bootstrap_rollouts (LIFT #3) carries CP’s view of active rollouts the agent should rehydrate when its reducer was lost (boot-recovery shape; heartbeat carried rollout_id = None but CP holds non-terminal records for the host).
RuntimeHandle
Handle returned by spawn. Holds the input channel sender (cloneable for HTTP route handlers) and the reducer-task JoinHandle. The handle must outlive every cloned sender, otherwise the reducer task exits prematurely.
ShutdownToken
Shutdown signal handed to a worker at spawn time. Workers select! between their input source and &mut self.0; reducer-task exit drops the matched Sender<()> and the receiver resolves with Err(RecvError). Workers treat any resolution as “shutdown” and exit cleanly.

Enums§

ReducerInput
Reducer-task inputs. Workers and HTTP route handlers obtain a mpsc::Sender<ReducerInput> from the RuntimeHandle and emit values of this type. Variants partition by the reducer action they drive:

Constants§

REDUCER_INPUT_CAPACITY 🔒
Input channel depth. Sized for ~512 in-flight events plus headroom for burst: a 256-host fleet, ~2 events/host during peak rollout activation, rounded to power-of-two and doubled. Backpressure surfaces at HTTP handlers via try_send → 503 (caller retries), preserving the pull-only agent contract (RFC-0005 §2.1 — CP never pushes, agents always retry).

Functions§

spawn
Spawn the reducer + worker constellation. Returns a RuntimeHandle the caller wires into the server shutdown drain.
spawn_drain_only_writer 🔒
Fallback writer when CP runs in in-memory mode (no db_path flag). Just drains entries silently so the channel never fills up. Production paths always configure a DB.