Skip to main content

WorkloopStore

Trait WorkloopStore 

Source
pub trait WorkloopStore:
    Send
    + Sync
    + 'static {
    // Required methods
    fn put_workloop<'life0, 'async_trait>(
        &'life0 self,
        record: WorkloopRecord,
    ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn get_workloop<'life0, 'life1, 'async_trait>(
        &'life0 self,
        loop_id: &'life1 WorkflowId,
    ) -> Pin<Box<dyn Future<Output = Result<Option<WorkloopRecord>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn list_workloops<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<WorkloopListing, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn due_workloops<'life0, 'async_trait>(
        &'life0 self,
        as_of: DateTime<Utc>,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<WorkloopRecord>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn remove_workloop<'life0, 'life1, 'async_trait>(
        &'life0 self,
        loop_id: &'life1 WorkflowId,
    ) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn put_invariant_record<'life0, 'async_trait>(
        &'life0 self,
        record: InvariantStateRecord,
        prune_before: DateTime<Utc>,
    ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn current_invariant_record<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        loop_id: &'life1 WorkflowId,
        invariant: &'life2 str,
    ) -> Pin<Box<dyn Future<Output = Result<Option<InvariantStateRecord>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn invariant_record_generations<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        loop_id: &'life1 WorkflowId,
        invariant: &'life2 str,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<InvariantStateRecord>, StoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
}
Expand description

Durable workloop persistence contract.

Required Methods§

Source

fn put_workloop<'life0, 'async_trait>( &'life0 self, record: WorkloopRecord, ) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Create or replace a loop’s registration record.

Source

fn get_workloop<'life0, 'life1, 'async_trait>( &'life0 self, loop_id: &'life1 WorkflowId, ) -> Pin<Box<dyn Future<Output = Result<Option<WorkloopRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Look up one loop by id.

Source

fn list_workloops<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<WorkloopListing, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List decodable loops and report every undecodable row, both ordered by loop id text.

Source

fn due_workloops<'life0, 'async_trait>( &'life0 self, as_of: DateTime<Utc>, ) -> Pin<Box<dyn Future<Output = Result<Vec<WorkloopRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Loops whose next_check_at is Some and at or before as_of — the sweeper’s work set. A sleeping loop with a future (or absent) check instant never appears, which is what makes a thousand sleeping loops cost the sweeper nothing. Undecodable rows are excluded here (they surface via WorkloopStore::list_workloops, never silently in the hot path).

Source

fn remove_workloop<'life0, 'life1, 'async_trait>( &'life0 self, loop_id: &'life1 WorkflowId, ) -> Pin<Box<dyn Future<Output = Result<bool, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove a loop’s registration (retirement). Returns whether a row existed. Invariant current-state records are NOT removed: the current record survives indefinitely by declaration (R8.1).

Source

fn put_invariant_record<'life0, 'async_trait>( &'life0 self, record: InvariantStateRecord, prune_before: DateTime<Utc>, ) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Install record as the invariant’s current record — rotating any prior current into the generation list — and prune prior generations recorded before prune_before, in ONE read-modify-write. Returns how many prior generations the prune removed. The current record is never pruned; it survives indefinitely by declaration (R8.1).

§🔴 THE INSTALL AND THE PRUNE ARE ONE COMMIT, DELIBERATELY

Both halves address the SAME key — one invariant’s slot — and the close path performs them back to back on every park. Two separate read-modify-write commits made a park cost 2 + 2N spine-linear commits for N declared invariants; folding them makes it 2 + N. The second commit read back bytes the first had just written, paid a second durable round trip for them, and could interleave with nothing useful: a park between them would observe a slot whose retention window had not yet been applied. One commit removes both the cost and that window.

Retention is therefore not a separate verb that a caller could forget: installing a record IS what prunes the ones it aged out, so declared retention is retention that happens.

Source

fn current_invariant_record<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, loop_id: &'life1 WorkflowId, invariant: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Option<InvariantStateRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

The invariant’s current record, if one was ever produced.

Source

fn invariant_record_generations<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, loop_id: &'life1 WorkflowId, invariant: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<InvariantStateRecord>, StoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

The invariant’s prior generations within retention, oldest first.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§