vertep-runtime turns a W3C SCXML chart into a durable actor. An actor has an IRI address
and a mailbox. Each turn takes one message, runs one SCXML macrostep with the pure step of
vertep-core, and appends one journal entry with compare-and-set. Only after the append
succeeds are the turn's sends dispatched. Delayed sends are durable timers in the journal, so
they fire after a restart. An actor's state at any past position can be rebuilt by replay.
The runtime is a shell around the pure core: time, spawning and sleeping come in through a
Shell, so tests run on a virtual clock. It stores journals through the traits of
vertep-store, on MemoryStore, on vertep-tiramemsu (feature tiramemsu) or on any
Storage you write. vertep-agent, vertep-cluster and vertep-federation build on it.
The vertep facade turns it on with its default runtime feature and re-exports it as
vertep::runtime, with the common types in vertep::prelude. Most applications should depend
on vertep. Depend on this crate directly to pick the storage backend and features yourself.
Install
[]
= { = "0.1", = ["tiramemsu"] }
= "0.1" # Event, EventType, Chart
= "0.1" # read SCXML documents into a Chart
= { = "1", = ["rt", "macros", "time"] } # for Shell::tokio() and node.run()
| Feature | Turns on |
|---|---|
tiramemsu |
Storage for TiramemsuShard and TiramemsuBackend, the default durable backend |
websocket |
websocket::server, the server end of the WebSocket Event I/O Processor (tokio-tungstenite). The frames and link state are always built |
With no features, the runtime runs on vertep_store::MemoryStore or on a SplitStorage you
assemble from any journal store and graph store.
Example
use Arc;
use Duration;
use ;
use ;
use MemoryStore;
const ORDER: &str = r#"<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="open">
<state id="open">
<transition event="pay" target="paid"><send event="ship" delay="200ms"/></transition>
</state>
<state id="paid"><transition event="ship" target="shipped"/></state>
<state id="shipped"/>
</scxml>"#;
const ORDER_TYPE: &str = "https://example.org/charts/order";
The first node accepts pay and writes entry 1, which records the delayed ship send as a
durable timer. That node is then dropped. A second node on the same store finds the pending
timer, and when the virtual clock reaches its due time the timer becomes entry 2. state_at
rebuilds the state after entry 1 by replay, without touching the live actor. A server uses
Shell::tokio() and node.run().await inside a tokio::task::LocalSet instead of the virtual
clock; see the facade's quickstart.
Key types
| Item | What it is |
|---|---|
Node, NodeBuilder, NodeConfig |
the scheduler of one process: register_type, send, run, run_until_idle, state, state_at, journal, migrate, fork, dead_letters, pending_timers |
NodeHandle |
a Send + Sync handle to a running node: send, ask (send and wait for a vt:reply), shutdown |
Address |
an actor's IRI; Address::virtual_actor(chart_type, key) |
Shell, Clock, Spawn, Sleep, VirtualClock |
the async seam: Shell::tokio() for servers, Shell::virtual_time(ms) for tests |
Storage, SplitStorage |
a journal store plus the graph stores for current state, snapshots, outbox marks and mailboxes; implemented for MemoryStore and, with tiramemsu, the tiramemsu types |
Mailbox, MemoryMailboxes, StoreMailboxes |
in-memory or store-backed mailboxes, set per node or per IRI scheme |
Transport, LocalTransport, Resolver |
SCXML Event I/O Processors selected by <send type="...">, and the directory of resolvers per IRI scheme |
Actor, ChartActor, FnActor, StreamActor |
the actor contract and its adapters for <invoke> children and worker pools |
ChartRegistry, ChartInfo, Migration |
content-addressed chart versions (urn:vertep:chart:sha256:...) and explicit migrations between them |
EntryData, EntryBody, TimerRecord |
journal entries decoded from RDF |
ontology, vocab |
the runtime ontology, its SHACL shapes and the vt: IRIs |
Placement, Route |
the hook a cluster uses to place actors on nodes |
The vt: extensions the runtime reads from charts include <vt:request> (ask another actor
and wait without blocking), vt:defer (keep matching events in the mailbox), vt:unhandled,
<vt:reminder> (recurring durable timers), vt:restart supervision on <invoke>, and
<vt:migrate>.
Known limits: a Node runs on one thread because datamodels need not be Send; run it in a
LocalSet and reach it from elsewhere through node.handle(). An invoked child chart has no
journal of its own and is rebuilt by replaying its parent, so a child that must outlive its
node should be a virtual actor reached by <send>.
Documentation
- Website: https://volland.github.io/vertep/ (The actor runtime)
- API reference: https://docs.rs/vertep-runtime
- Examples: https://volland.github.io/vertep/examples/ (durable actor)
License
MIT OR Apache-2.0, at your option.