Expand description
Itinera is a workflow framework that keeps business rules separate from flow control.
Its behaviour is defined by the Itinera specification,
whose vocabulary this crate uses. This release implements tier 1 of specification 0.1.0,
with the capabilities sync, async and testing, and passes its conformance cases
v0.1.0-rc.15.
To learn Itinera step by step, read the Itinera book for Rust, where every example compiles and runs. The Itinera site explains why Itinera exists. This documentation is the reference for each item.
§The parts of a workflow
- A step holds one business rule. It declares the data it needs, which the workflow
supplies, runs once per attempt, and reports an outcome: success, failure or skipped. Only an
attempt that succeeds commits what the step contributed. A step may have a rescue step,
which runs when the step fails or terminates abnormally and, once it succeeds, lets the step
run again. See
step. - A service is an object of operations a step uses to do its business, such as a payment
gateway. The step requests it by key, and a service provider of the workflow makes it, for
the journey or for each attempt. See
service. - A policy holds flow control. Its hooks, such as
on step failureoron workflow success, are called in response to a step’s outcome or at the end of the journey, and may end the journey early. A hook may use a role, an interface the workflow provides. Seepolicy. - A workflow lists its steps in the order they run, with their retry budgets and policies,
its own policies, its input adapters, its service providers, its ID generator and its
reporters. It is declared once, before any journey, and a declaration that breaks a rule of
the specification is refused. See
workflow. - A workflow instance is created for each journey, with its initial data, its reporters and
any initial global metadata, and an executor runs it to a result: the journey
succeeded, failed or was aborted. See
instance,executorandjourney. - Everything that happens in a journey is an event, which the journey’s reporters receive,
together with the journey’s global metadata: entries of a key and a value, apart from
the data bag, starting with the journey ID. See
eventandreport.
§A first workflow
A workflow of one step, which charges an order’s price, with a step policy that audits each charge. The order is given as the journey’s initial data, and the receipt is read from its output.
use itinera::error::Error;
use itinera::executor::LocalExecutor;
use itinera::journey::{Contributor, InitialData, Output};
use itinera::policy::{OnSuccess, step_policy};
use itinera::step::{Outcome, Step, step};
use itinera::workflow::workflow;
#[derive(Step)]
struct Charge {
#[input]
price: i64,
}
#[step]
impl Charge {
fn run(self, #[contributor] mut contributor: Contributor<'_>) -> Result<Outcome, Error> {
if self.price <= 0 {
return Self::fail("nothing-to-charge");
}
contributor.contribute("charged", self.price);
Self::succeed()
}
}
#[derive(Default)]
struct Audit;
#[step_policy(name = "audit")]
impl Audit {
#[on_step_success]
fn audited(
&self,
#[from_step] charged: i64,
#[contributor] mut contributor: Contributor<'_>,
) -> Result<Option<OnSuccess>, Error> {
contributor.contribute("audit", format!("charged {charged}"));
Self::carry_on()
}
}
#[workflow(name = "orders")]
#[with_step(Charge, name = "charge", retry_budget = 2, policies = [Audit])]
struct Orders;
#[derive(InitialData)]
struct NewOrder {
price: i64,
}
#[derive(Output)]
struct Receipt {
charged: i64,
audit: String,
}
let instance = Orders::builder()
.initial_data(NewOrder { price: 40 })
.create()?;
let receipt: Receipt = LocalExecutor::new().run(instance)?.output()?;
assert_eq!(receipt.charged, 40);
assert_eq!(receipt.audit, "charged 40");The crate’s examples go further: orders adds a second step, a workflow policy using a role,
an input adapter, an ID generator and a reporter; orders_async runs the same workflow on the
asynchronous executor; and orders_by_hand declares it with the builder alone, without macros.
§Features
macros, on by default: the attributes and derives that declare steps, rescue steps, policies, workflows, roles and journey data. They expand to builder calls and implementations of public traits, which an application can write by hand.async: the asynchronous executor, and asynchronous steps, rescue steps, hooks, service providers, reporters and dispatchers, withmode::async_traitfor services and roles whose methods are asynchronous.testing: test support.report::RecordingReporter, a reporter that keeps every event, and the latest value of each entry of global metadata, for a test to read; fakes in place of service providers; scripted runs; and recorders that lend a step, a hook or an input adapter its handles outside a journey. Enable it for tests only, under[dev-dependencies].unstable: API the specification has not settled yet; empty for now.
Modules§
- error
- The error of custom code.
- event
- Events: the record of what happens in a journey, and what only events carry.
- executor
- Executors, which run workflow instances, and the refusals they give when a journey cannot start.
- instance
- Workflow instances: one per journey, holding its journey ID, its reporters and its data.
- journey
- Journeys, each one execution of a workflow: their identity, their data, and how they end.
- mode
- Execution modes: whether a workflow is synchronous or asynchronous.
- policy
- Policies: their descriptors, the hooks they define, what hooks request, the lifecycles they return, and the roles through which they reach a workflow.
- report
- Reporters, which receive the events and the global metadata of a journey, and dispatchers, which deliver them.
- service
- Services: objects of operations that steps use to do their business, and the service providers through which a workflow supplies them, for a journey or for each attempt.
- step
- Steps: the business units of a workflow, what they need, how they are built and run, their attempts, their outcomes and the reasons they give, and the rescue steps that fix the cause of a step’s failure.
- value
- Values: data that can be serialized, the only data a data bag, an event or a reason holds.
- workflow
- Workflows: their declaration, the workflow descriptor, shared by every instance.