zestors is an actor framework for Rust with Erlang/OTP-style supervision and
clustering.
An actor is a tokio task that owns an Inbox and handles the messages sent to
it. Messages are plain structs deriving Message, and the set of messages an
actor accepts is its Interface. A Supervisor starts, watches and restarts
its children according to a restart strategy, and a Node runs a supervision
tree as a program. Nodes can join a cluster, where an actor on another node is
messaged just like a local one.
- An actor is just a task. No actor system to start: spawn an async closure
over an
Inboxin any tokio runtime andselect!over whatever it needs — or implement oneHandle<M>per message and letHandlerrun the loop. - A message means the same thing to every actor. Its reply type belongs to
the message, not to the receiver, so one message (
GetHealth) can be asked of any actor that accepts it. - Address actors by what they accept.
Address<Dyn<(GetHealth, GetChildren)>>has the same type for unrelated actors that share those messages. The supervision tree, HTTP API and inspector explore a running system this way, without knowing any actor's type. - Supervision in the OTP sense. Actors restart on the same channel, so names and addresses stay valid across restarts; strategies, restart budgets and dynamic child sets are plain data.
- Local or remote, the same code. A
ClusterAddressreaches an actor on any node with the samecastandcall, over QUIC with mutual TLS. The network's semantics are spelled out, and clusters can be tested in one process on virtual time.
Warning
Distributed mode is not production ready. Its APIs are bound to change,
and there will be bugs. It is behind the distr feature, which is off by
default. The rest of the framework — actors, messaging and
supervision — is the mature part.
A worker, written as a Handler, supervised by a Supervisor that runs as a
program with Node:
use zestors::interface::{Envelope, Interface, Message};
use zestors::prelude::*;
use zestors::supervisor::{Node, Supervisor};
#[derive(Message, Debug)]
struct Ping;
#[derive(Interface, HandlerInterface, Debug)]
enum WorkerInterface {
Ping(Envelope<Ping>),
}
#[derive(Debug, Clone)]
struct Worker;
impl Handler for Worker {
type Interface = WorkerInterface;
}
impl Handle<Ping> for Worker {
async fn handle(
&mut self,
_ctx: HandlerContext<'_, Self>,
_msg: Ping,
_req: (),
) -> Result<(), rootcause::Report> {
Ok(())
}
}
#[tokio::main]
async fn main() {
let node = Node::new(
Supervisor::blueprint()
.child(Worker.name("worker").unwrap())
.rand_name(),
);
// Starts the supervisor, and shuts it down gracefully on Ctrl+C/SIGTERM.
node.run().await.unwrap();
}[dependencies]
zestors = "0.3"
tokio = { version = "1", features = ["full"] }
rootcause = "0.13"- The zestors book: the guide, from a first actor to supervision trees and clusters.
- API documentation: every type in detail.
- Examples in
crates/zestors/examples:supervision(a supervision tree with the HTTP API), and, with--features distr,remote(two cluster nodes in one process) andcluster(one node per terminal).
A proof-of-concept inspector GUI draws a running supervision tree; see Observability.
Most programs depend only on the zestors crate, which
re-exports the others as modules.
| Crate | What it provides |
|---|---|
zestors |
The facade: re-exports the others, and a prelude. Start here. |
zestors-interface |
Message/Interface: what an actor accepts, and how it replies. |
zestors-runtime |
Inbox, Address, Child, Name, the Registry, signals, statuses and dynamic addresses. |
zestors-actor |
Handler/Actor: declarative and low-level ways to implement an actor; Blueprint. |
zestors-supervision |
ChildSpec/ChildConfig/RestartIntensity, and the GetChildren/GetHealth queries. |
zestors-supervisor |
The Supervisor actor, and Node to run one as a program. |
zestors-distr |
Clustering: ClusterNode, Cluster, ClusterAddress, remote messages. |
zestors-distr-quic |
The QUIC transport for clusters, with mutual TLS. |
zestors-distr-backend |
The transport trait, to run a cluster over another network. |
zestors-api-server |
An HTTP server for inspecting a running supervision tree. |
zestors-codegen |
The Message, Interface, HandlerInterface and StableId derive macros. |
zestors-inspector |
A GUI for the data zestors-api-server serves (not re-exported by zestors). |
AI agents were used to write parts of the documentation and the implementation, always paired with human supervision and thorough analysis of what they produced. The core of zestors — its actors, messaging and supervision — was crafted and coded by hand, with love and attention to detail.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.