Browse documentation
Your first durable actor
Set a counter, let the process exit, then read the same state from another process.
Create a counter, change its value, then read it from a different process. You will see an actor’s state outlive the process that handled its message.
This source-checkout route requires access to the runtime source repository and a matching checkout on Linux or macOS. Run the commands from that repository root in the same shell. The example files are included in the checkout. Public installation details belong to the release distribution; this guide does not require a cloud account.
1. Build the runtime once
scripts/build-runtime --check
scripts/build-runtime
The first command checks the pinned Rust toolchain and C build prerequisites, reporting a remedy for anything missing. The second builds the runtime with its committed dependency lockfile. Building may require network access for missing dependencies. On macOS the C prerequisites include the Xcode Command Line Tools.
Copy and run the export PATH=… line printed by the build script. The commands below then use that executable to check and run application source. This is the one-time runtime build, separate from the application edit loop.
2. Meet the counter
The example’s source, examples/migrating-counter/before/src/lib.rs, contains this actor:
use effectful::{cast, durable_server, State};
#[derive(State)]
pub struct State {
pub count: i64,
}
#[durable_server(state = State, name = "counter", version = 1)]
impl State {
#[cast]
pub fn set(&mut self, count: i64) {
self.count = count;
}
}
State is what the actor remembers. durable_server names its behaviour. cast makes set a message handler. The surrounding example supplies the manifests and input files.
Check the application:
app="$PWD/examples/migrating-counter"
effectful graph check "$app/start"
Here, graph means the application and its Rust library sources. Checking reads and validates that source; it does not create a counter.
3. Create an actor with a count of 7
Use a new scratch directory so the example has its own saved state:
work=$(mktemp -d)
state="$work/state"
effectful graph spawn "$app/start" --state "$state" \
--behavior counter --key demo --init "$app/initial.json" \
> "$work/spawn.txt"
cat "$work/spawn.txt"
The output includes a run1-… identity. It identifies the actor, not the process that created it. Extract it and read the state:
run=$(sed -n 's/^run \(run1-[0-9a-f]*\) .*/\1/p' "$work/spawn.txt")
effectful graph state --state "$state" --run "$run"
The output contains ["s64","7"], the CLI’s explicit representation of the saved integer. The example provides the input encoding, so you do not need to construct it yet.
4. Send one change
The supplied message calls set with 11:
effectful graph cast --state "$state" --run "$run" \
--message "$app/message.json"
effectful graph state --state "$state" --run "$run"
The saved integer is now 11. Run the final command again. It reads the same value even though each line starts a fresh process.
5. Inspect what remains
effectful inspect "$run" --state "$state"
Look for the saved integer 11, a receive point (kind: Receive) and an empty mailbox. The actor is waiting for another message.
You have demonstrated persistence across process reopening. This exercise does not inject a crash during a write or validate an external service’s delivery behaviour.
What just happened?
The process was temporary; the actor identity and node history were durable. The state directory connects the commands. A new process can reopen it and reconstruct the actor’s state.
Keep the directory and actor identity if you want to continue. You can print them for your notes:
printf '%s\n' "$state" "$run"
Treat the directory as a whole persisted node. Do not edit individual storage files to change the actor.
Next, read the system model or build a library and its consumer.
Build software you can reason about.