streamline
Reversible Stream-based state machine library for Rust
Example
Here's an example of how to use a Streamline to create a GitHub repo, Tweet about it, and reverse the whole process if something goes wrong.
// recommended, but not required
use async_trait;
// some example clients for communicating through third-party APIs
use ;
use StreamExt;
use ;
const MY_USERNAME: &'static str = "my-github-username";
// clients are stored in context for shared access throughout the life of the streamline
// you should create better errors than this
type MyError = ;
async
Motivation
If one wants to move from one state to the next within a process, it makes sense in Rust to look towards some of the many state machine patterns available through the type system. enums, in particular, are a great way of modeling the progress of a process in a way that excludes impossible states along the way. But there's less certainty around handling state for the following scenarios:
- Non-blocking state updates: it's often the case that we care most about the final state of a state machine, but we would also like to be updated when the state changes along the way to that terminal state. In state machines, this is often implemented as a side effect (e.g. through channels or an event broker).
- Super-statefulness: while it's common to carry state around inside individual variants of an
enum, it's much trickier to know when to handle updates to state that is not directly attached to a single variant of the state machine. How does one, for example, handle updating a value in a database as a state machine progresses? What about interacting with third-party services? When should these parts of state be handled? - Reversibility: most processes need to know how to clean up after themselves. Modeling these fallible processes and their path towards full reversion to the original state (or failure to do so) is a complex and boilerplate-heavy process.
- Cancellation: interrupting the execution of a
Streamis easy... just drop theStream! But cleaning up after a stream that represents some in-progress state is much more difficult.
streamline solves addresses those problems in the following ways:
futures::Stream-compatibility: rather than using side effects during state machine execution, this library models every update to a state machine as anItemin astd::futures::Stream.- Consistent
Context: all super-variant state can be accessed with a consistentContext. - Automatic Reversion: whenever a process returns an
Err,streamlinewill (optionally) revert all the states up to that point, returning the original error. - Manual Cancellation: the
run_preemptiblemethod returns aStreamand aCancelhandler that can be used to trigger the revert process of a working stream.