use memable::{Context, Engine, EngineError, MetadataStatus, SuspendPoint, WorkflowState};
const APPROVAL: SuspendPoint<bool> = SuspendPoint::new("approval:v1");
async fn approval_workflow(ctx: Context) -> Result<(), EngineError> {
let record_count: u32 = ctx
.step("fetch-data:v1")
.run(async || {
println!(" [step] fetching data from source");
Ok(142)
})
.await?;
let approved: bool = ctx
.suspend(&APPROVAL)
.status("Waiting for manager approval")
.await?;
if !approved {
println!(" [workflow] approval denied — aborting");
return Ok(());
}
let _processed: u32 = ctx
.step("process-data:v1")
.run(async move || {
println!(" [step] processing {record_count} approved records");
Ok(record_count)
})
.await?;
println!(" [workflow] done — processed {record_count} records");
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut engine = Engine::builder().in_memory().build();
engine.register("approval", approval_workflow);
engine.start().await?;
println!("=== Invoking workflow ===");
let inv = engine.invoke("approval").await?;
let instance_id = inv.instance_id().to_string();
let state = inv.wait().await;
println!("State: {state}");
let meta = engine
.get_metadata("approval", &instance_id)?
.expect("instance exists");
println!("Metadata: {}", meta.status());
assert!(matches!(
meta.status(),
MetadataStatus::Suspended { status, .. } if status == "Waiting for manager approval"
));
println!();
println!("=== Sending approval signal ===");
let state = engine
.signal("approval", &instance_id, &APPROVAL, true)
.await?
.wait()
.await;
println!("State: {state}");
assert_eq!(state, WorkflowState::Completed(None));
let meta = engine
.get_metadata("approval", &instance_id)?
.expect("instance exists");
println!("Metadata: {}", meta.status());
engine.stop().await;
Ok(())
}