Skip to main content

ExecutorFactory

Trait ExecutorFactory 

Source
pub trait ExecutorFactory: Send + Sync {
    type Workflow: WorkflowDefinition;
    type Executor: WorkflowExecutor<Self::Workflow> + Send + Sync;

    // Required methods
    fn seed<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<SeedOf<Self>, String>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn interrupt_after<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        seeded: &'life1 SeedOf<Self>,
        batch: &'life2 BatchOf<Self>,
        applied: usize,
    ) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
}
Expand description

Builds a fresh executor with one case in it, once per check.

§The seed must be deterministic

seed is called more than once inside a single check — check_interrupted_batch_resumes_to_the_same_state compares an interrupted run against an uninterrupted one — and the two runs are only comparable if both start from the same state at the same revision, with the same account and case identifier. A factory that mints a random case id per call, or reuses one executor across calls, makes that check meaningless rather than failing it.

The seeded revision may be anything, including CaseRevision::ZERO for a case that does not exist yet, as long as case_ref.expected_revision is the revision load reports.

Required Associated Types§

Source

type Workflow: WorkflowDefinition

The workflow whose executor is under test.

Source

type Executor: WorkflowExecutor<Self::Workflow> + Send + Sync

The executor implementation being proven.

Required Methods§

Source

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

Builds a fresh executor and seeds one case in it.

§Errors
  • A description of what went wrong while building or seeding. The suite turns it into a ConformanceFailure for the check that asked.
Source

fn interrupt_after<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, seeded: &'life1 SeedOf<Self>, batch: &'life2 BatchOf<Self>, applied: usize, ) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Commits only the first applied envelopes of batch, as a process that died mid-batch would have left them.

This is the one thing the suite cannot do through WorkflowExecutor, and the check that matters most needs it. Implement it against your own tables, with the same code path execute uses, stopping after applied envelopes have committed.

If a partial batch is impossible in your executor — every envelope commits inside one database transaction, so a crash rolls all of them back — then implement this by executing the whole batch and returning Ok(()). That is the honest translation: the state a crash can leave behind is either “none of it”, which needs no resume, or “all of it”, which the resume must recognise as a replay. The checks then prove that stronger property instead of a weaker one.

§Errors
  • A description of why the prefix could not be committed. applied is always at least one and never larger than the batch, so a bounds complaint is a bug in the suite, not in the implementation.

Dyn Compatibility§

This trait is dyn compatible.

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

Implementors§