pub struct CommandExecutor { /* private fields */ }Expand description
Runs command batches against the domain, the journal and the outbox.
Implementations§
Source§impl CommandExecutor
impl CommandExecutor
Sourcepub fn new(
workflows: Arc<WorkflowRegistry>,
journal: Arc<dyn CommandJournal>,
commit: Arc<dyn CommitStore>,
outbox: Arc<dyn OutboxStore>,
config: ExecutionConfig,
) -> Self
pub fn new( workflows: Arc<WorkflowRegistry>, journal: Arc<dyn CommandJournal>, commit: Arc<dyn CommitStore>, outbox: Arc<dyn OutboxStore>, config: ExecutionConfig, ) -> Self
Builds an executor.
Sourcepub const fn config(&self) -> &ExecutionConfig
pub const fn config(&self) -> &ExecutionConfig
The execution configuration in force.
Sourcepub async fn journal_pending(
&self,
batches: &[CommandBatch<Value>],
now: DateTime<Utc>,
) -> Result<Vec<CommandId>, OrchestratorError>
pub async fn journal_pending( &self, batches: &[CommandBatch<Value>], now: DateTime<Utc>, ) -> Result<Vec<CommandId>, OrchestratorError>
Admits the commands a confirmation card will authorize, in Pending
(spec §15.3).
They do not run: the card names them, and a later click resumes exactly these entries by idempotency key. Re-journaling the same entry (a replayed turn) is accepted and changes nothing.
§Errors
OrchestratorError::Store when the journal could not be written.
Sourcepub async fn resume_confirmed(
&self,
account: &AccountId,
command_refs: &[CommandRef],
origin: &CommandOrigin,
actor: &ActorContext,
turn_id: TurnId,
) -> Result<Vec<CommandBatch<Value>>, OrchestratorError>
pub async fn resume_confirmed( &self, account: &AccountId, command_refs: &[CommandRef], origin: &CommandOrigin, actor: &ActorContext, turn_id: TurnId, ) -> Result<Vec<CommandBatch<Value>>, OrchestratorError>
Rebuilds the batches a confirmed card authorized, from the journal entries the card names (spec §15.3).
The commands come back exactly as they were reviewed, with the
idempotency key they were admitted under, so answering the card twice
cannot execute twice. The origin replaces the one recorded at
admission: the authority is now the click, and policy is re-checked
against it.
The rebuilt batches carry AtomicityScope::PerCase, which is what a
reviewed set has to be: the user confirmed one change to one case, so
its commands commit together or not at all.
Every rebuilt envelope is policed again before it is returned: the
domain’s CommandPolicy for
the command, against the origin the click minted
(origin_satisfies). The
card was built for exactly these commands under exactly that policy, so
the check should never fire — which is the point of running it. A
command it refuses is dropped rather than executed.
§Errors
OrchestratorError::Store when an entry named by the card is not in
the journal for this account.
Sourcepub async fn admit(
&self,
envelope: &CommandEnvelope<Value>,
now: DateTime<Utc>,
) -> Result<Admission, OrchestratorError>
pub async fn admit( &self, envelope: &CommandEnvelope<Value>, now: DateTime<Utc>, ) -> Result<Admission, OrchestratorError>
Admits one envelope to the journal, before anything runs (§16.2, I14).
This is the single door every effect goes through, and it is public because an adopter driving execution themselves has to go through it too. The three answers are the whole contract: the key is new, the key is there and unsettled (resume it — never re-plan it), or the key is there with an outcome (return that outcome and run nothing).
§Errors
OrchestratorError::Storewhen the journal could not be written;OrchestratorError::ExecutionwithExecutionError::IdempotencyMismatchwhen the key names a different command, which is a defect nobody may guess past.
Sourcepub async fn execute(
&self,
account: &AccountId,
batches: &[CommandBatch<Value>],
now: DateTime<Utc>,
) -> Result<ExecutionReport, OrchestratorError>
pub async fn execute( &self, account: &AccountId, batches: &[CommandBatch<Value>], now: DateTime<Utc>, ) -> Result<ExecutionReport, OrchestratorError>
Executes every batch (spec §23 step M).
Batches run in order. When
ExecutionConfig::allow_cross_case_partial_success is off, the first
batch that does not commit stops the rest: a turn that half-happened
across two cases is harder to explain than one that did not start.
§Errors
OrchestratorError::Store when the journal itself could not be
reached. A command that merely failed is not an error here: it is an
outcome, and it is reported as one.
Sourcepub async fn commit(
&self,
account: &AccountId,
bundle: CommitBundle,
) -> Result<CommitReceipt, OrchestratorError>
pub async fn commit( &self, account: &AccountId, bundle: CommitBundle, ) -> Result<CommitReceipt, OrchestratorError>
Writes the bundle, all or nothing (spec §16.3, §23 step N).
§Errors
OrchestratorError::Store. A StoreError::Timeout means the write
may have landed: the caller must re-read rather than retry, and the
bundle’s own atomicity guarantees that whatever it finds is either all
of it or none of it (§16.5).
Sourcepub fn outbox(&self) -> &Arc<dyn OutboxStore> ⓘ
pub fn outbox(&self) -> &Arc<dyn OutboxStore> ⓘ
The outbox the dispatcher reads, for callers that reconcile from the same executor.
Sourcepub fn journal(&self) -> &Arc<dyn CommandJournal> ⓘ
pub fn journal(&self) -> &Arc<dyn CommandJournal> ⓘ
The command journal.