Skip to content

Run your Rust CLI programs as state machines with persistence and recovery abilities

Notifications You must be signed in to change notification settings

imbolc/step-machine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

version-badge docs-badge license-badge

step-machine

Run your CLI programs as state machines with persistence and recovery abilities. When such a program breaks you'll have opportunity to change the external world (create a missing folder, change a file permissions or something) and continue the program from the step it was interrupted on.

Usage

Let's toss two coins and make sure they both landed on the same side. We express the behaviour as two states of our machine. Step logic is implemented in State::next() methods which return the next state or None for the last step (the full code is in examples/coin.rs).

#[derive(Debug, Serialize, Deserialize, From)]
enum Machine {
    FirstToss(FirstToss),
    SecondToss(SecondToss),
}

#[derive(Debug, Serialize, Deserialize)]
struct FirstToss;
impl FirstToss {
    fn next(self) -> StepResult {
        let first_coin = Coin::toss();
        println!("First coin: {:?}", first_coin);
        Ok(Some(SecondToss { first_coin }.into()))
    }
}

#[derive(Debug, Serialize, Deserialize)]
struct SecondToss {
    first_coin: Coin,
}
impl SecondToss {
    fn next(self) -> StepResult {
        let second_coin = Coin::toss();
        println!("Second coin: {:?}", second_coin);
        ensure!(second_coin == self.first_coin, "Coins landed differently");
        println!("Coins match");
        Ok(None)
    }
}

Then we start our machine like this:

let init_state = FirstToss.into();
let mut engine = Engine::<Machine>::new(init_state)?.restore()?;
engine.drop_error()?;
engine.run()?;

We initialize the Engine with the first step. Then we restore the previous state if the process was interrupted (e.g. by an error). Then we drop a possible error and run all the steps to completion.

Let's run it now:

$ cargo run --example coin
First coin: Heads
Second coin: Tails
Error: Coins landed differently

We weren't lucky this time and the program resulted in an error. Let's run it again:

$ cargo run --example coin
Second coin: Heads
Coins match

Notice that, thanks to the restore(), our machine run from the step it was interrupted, knowing about the first coin landed on heads.

About

Run your Rust CLI programs as state machines with persistence and recovery abilities

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages