LauncherSagaLog

Struct LauncherSagaLog 

Source
pub struct LauncherSagaLog {
    conn: Mutex<Connection>,
}
Expand description

SQLite-backed launcher saga log. Owned by SagaCoordinator as Arc<LauncherSagaLog> once PR LSD-2 wires it; PR LSD-1 only constructs and tests it in isolation.

Fields§

§conn: Mutex<Connection>

Implementations§

Source§

impl LauncherSagaLog

Source

pub fn open(path: &Path) -> Result<Self, LogError>

Open a saga log backed by the given SQLite file. Configures WAL mode + 5s busy timeout + foreign_keys=ON (mirroring SagaLog::open in agentmux-srv/src/sagas/log.rs) and applies the schema migration from schema.rs.

Idempotent: reopening the same DB applies the same DDL via CREATE TABLE IF NOT EXISTS — no double-creation, no error.

Source

pub fn open_read_only(path: &Path) -> Result<Self, LogError>

Open the saga log in read-only mode. Used by --diag sagas so an operator’s diagnostic invocation can’t accidentally schema-migrate or modify a log that a running launcher owns. Skips configure_and_migrate (read-only opens shouldn’t run migrations) and skips the foreign_keys=ON pragma since we don’t write. (codex P2 PR #647 round 3.)

Source

pub fn open_in_memory() -> Result<Self, LogError>

Open an in-memory saga log for testing. Used by tests.rs and by future PR LSD-2 coordinator integration tests.

Source

fn configure_and_migrate(conn: Connection) -> Result<Self, LogError>

Source

pub fn max_saga_id(&self) -> Result<u64, LogError>

Highest existing saga_id in the durable log, or 0 if empty. PR LSD-2 calls this at coordinator startup to seed next_saga_id so a launcher restart doesn’t reuse ids that already have rows in the log.

Source

pub fn start_saga( &self, saga_id: u64, name: &str, input: &Value, ) -> Result<(), LogError>

Insert a fresh saga row in running state. Plain INSERT (not OR REPLACE): a duplicate saga_id is a bug worth surfacing, not a silent overwrite. Same rationale as srv’s start_saga (codex P1 + reagent P1 PR #631).

Source

pub fn terminate_saga( &self, saga_id: u64, outcome: SagaOutcome, ) -> Result<(), LogError>

Write a saga’s terminal lifecycle row. Called by PR LSD-2’s apply_action when the saga returns Done / Failed. The recovery walker uses mark_failed_compensation instead.

Source

pub fn start_step( &self, saga_id: u64, step_index: u32, name: &str, target: PipeTarget, cmd: &Command, ) -> Result<(), LogError>

Insert a pending step row before dispatching the command. name is a short discriminant string (e.g. “issue_cmd_host_reap_panes”); cmd is serialized as JSON for replay/debugging; target records which pipe the command was destined for so --diag sagas can show provenance.

Source

pub fn finish_step( &self, saga_id: u64, step_index: u32, output: &Event, ) -> Result<(), LogError>

Mark a step succeeded and store the awaited event as JSON. PR LSD-2 calls this from route_event_to_sagas when a saga’s on_event consumes its awaited bus event.

Source

pub fn fail_step( &self, saga_id: u64, step_index: u32, reason: &str, ) -> Result<(), LogError>

Mark a step failed. Stores the reason in the step’s failure_reason column (distinct from srv’s log, which stuffs the reason into output_json as {"error": ...}; LSD schema gives us a dedicated column so we use it).

Source

pub fn unresolved_sagas(&self) -> Result<Vec<UnresolvedLauncherSaga>, LogError>

Return all sagas still in running, compensating, or failed state, each with its full step list. PR LSD-3’s startup recovery walker iterates this list and calls mark_failed_compensation on each (LSD spec §3.5).

failed is included for symmetry with srv’s unresolved_sagas (codex P1 PR #631 round 2): a launcher saga marked failed without restart-time recovery would still benefit from the failed_compensation upgrade so --diag sagas consistently surfaces it as “needs operator attention.”

Source

pub fn get_saga_steps( &self, saga_id: u64, ) -> Result<Vec<UnresolvedLauncherStep>, LogError>

Fetch the step rows for a single saga regardless of saga state. unresolved_sagas filters out failed_compensation (and other terminal states), but --diag sagas needs to surface step rows for sagas the recovery walker just marked failed_compensation — operators triaging a recovered crash need to see what was pending when the launcher exited. (codex P1 PR #647 round 1.)

Source

pub fn mark_failed_compensation( &self, saga_id: u64, reason: &str, ) -> Result<(), LogError>

Mark a saga as failed_compensation — the recovery walker’s terminal write. Idempotent across repeated calls (the saga stays in failed_compensation; ended_at is rewritten to the latest call’s timestamp; failure_reason is preserved when already populated and the new reason is APPENDED rather than overwritten — see SQL CASE WHEN below). This preserves the original failure cause (e.g. timeout) while adding the recovery context. (codex P2 PR #647 round 1: post-mortem preservation.) LSD spec §3.5 — operator-review terminal state.

Source

pub fn snapshot_recent( &self, limit: usize, ) -> Result<Vec<SagaSummary>, LogError>

Return up to limit recent sagas for --diag sagas. Sorted most-recent-first by COALESCE(ended_at, started_at). Mirrors srv’s snapshot_recent shape.

Source

pub fn vacuum_older_than( &self, cutoff: DateTime<Utc>, ) -> Result<usize, LogError>

Delete saga rows whose ended_at is before cutoff AND whose state is terminal (completed, failed, failed_compensation). Returns the number of rows deleted. In-flight sagas (running, compensating) are NEVER vacuumed — that would mask crashed-mid-saga incidents from the recovery walker (LSD spec §3.6).

ON DELETE CASCADE on launcher_saga_step.saga_id ensures the corresponding step rows go with the saga in a single SQLite transaction — no manual cleanup needed.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more