pub trait Skill:
Send
+ Sync
+ Debug
+ 'static {
// Required methods
fn descriptor(&self) -> SkillDescriptor;
fn invoke<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cx: &'life1 mut StepCtx<'life2>,
input: Tainted<Value>,
) -> Pin<Box<dyn Future<Output = Result<Outcome, SkillError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
// Provided methods
fn compensation(&self) -> Compensation { ... }
fn compensate<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_cx: &'life1 mut StepCtx<'life2>,
_output: &'life3 Tainted<Value>,
) -> Pin<Box<dyn Future<Output = Result<(), SkillError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
}Expand description
A stateless unit of logic.
Statelessness is not a style preference: it is what makes replay sound. All state lives in the journal, so re-running a skill against a replayed context reproduces its decisions exactly.
Note the absent variant: there is no Outcome::SuspensionRequired. Suspension
is cx.suspend().await, so skill authors never hand-roll state
serialization — the runtime persists the frame and drops the task.
Required Methods§
fn descriptor(&self) -> SkillDescriptor
fn invoke<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cx: &'life1 mut StepCtx<'life2>,
input: Tainted<Value>,
) -> Pin<Box<dyn Future<Output = Result<Outcome, SkillError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Provided Methods§
Sourcefn compensation(&self) -> Compensation
fn compensation(&self) -> Compensation
This step’s place in the saga.
Defaults to Compensation::Undeclared, which is resolved against the
journal rather than waved through — see that variant.
Sourcefn compensate<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_cx: &'life1 mut StepCtx<'life2>,
_output: &'life3 Tainted<Value>,
) -> Pin<Box<dyn Future<Output = Result<(), SkillError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn compensate<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_cx: &'life1 mut StepCtx<'life2>,
_output: &'life3 Tainted<Value>,
) -> Pin<Box<dyn Future<Output = Result<(), SkillError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Undo this step, because a later one failed.
Called in reverse order of completion, with the output this step
produced. The context is a full StepCtx:
compensating effects are journaled, retried, reconciled, and replayed
exactly like forward ones, because they are exposed to the same world
and can fail the same ways.
Errors are not retried by unwinding further. A failed compensation is not a problem more compensation solves, so the run is quarantined and an operator is told which step could not be undone.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".