Fault-tolerant async actors on Tokio — a Zenoh-native fork of the kameo actor framework. Bombay keeps kameo's local actor core (single-writer message handling, supervision, links, a name registry) and is replacing its libp2p remote layer with a thin Zenoh Session layer, pairing with nexus for event-sourced, single-writer aggregates.
Status: the local actor core (forked from kameo 0.21) is in-tree and works today; the Zenoh remote layer and the nexus adapter are under active development. Until those land, the public API below is the kameo actor API. Process, roadmap, and engineering rules live in
CLAUDE.md.
Derive Actor, implement Message<M> for each message a type handles, spawn it, then ask (request/reply) or tell (fire-and-forget):
use bombay::prelude::*;
#[derive(Actor, Default)]
struct Counter {
count: i64,
}
struct Inc(u32);
impl Message<Inc> for Counter {
type Reply = i64;
async fn handle(&mut self, Inc(n): Inc, _ctx: &mut Context<Self, Self::Reply>) -> i64 {
self.count += n as i64;
self.count
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let counter = Counter::spawn(Counter::default());
let count = counter.ask(Inc(3)).await?; // request/reply -> 3
counter.tell(Inc(50)).await?; // fire-and-forget
println!("count = {count}");
Ok(())
}Everything below is re-exported from bombay::prelude:
- Actor —
#[derive(Actor)]orimpl Actorby hand. Lifecycle hooks:on_start,on_panic,on_link_died,on_stop. Spawn withActor::spawn,spawn_with_mailbox,spawn_in_thread, or build one withprepareand run it later. - Messages —
impl Message<M> for A { type Reply; async fn handle(&mut self, msg, ctx) -> Reply }. TheContextexposes the actor's ownActorRef, the reply channel (reply_sender),forward/try_forwardto another actor, andattach_streamforStreamMessage. ActorRef—ask(request/reply) andtell(fire-and-forget), each a builder:.mailbox_timeout(..),.reply_timeout(..),.send()/.try_send()/.blocking_send(),tell's.send_after(..),.forward(..), orawaitit directly (IntoFuture). Plusdowngrade()→WeakActorRef, strong/weak reference counts,link/unlink, and type-erasedRecipient/ReplyRecipient.- Reply — any
Replytype, includingResult<T, E>and infallible scalars/collections.ForwardedReply,DelegatedReply, and a single-useReplySenderfor replying out-of-band. - Supervision —
RestartPolicy(Permanent/Transient/Never),SupervisionStrategy(OneForOne/OneForAll/RestForOne), restart-intensity limits (max restarts within a sliding window), and death-watch via links +on_link_died. - Registry — a process-local
ActorRegistry: register an actor under a name, look it up, remove it. - Mailbox — bounded (
mailbox::bounded(n)) or unbounded (mailbox::unbounded()); backpressure viasendvs fail-fasttry_send. - Errors —
SendError(ActorNotRunning/ActorStopped/MailboxFull/HandlerError/Timeout),PanicError,ActorStopReason.
Runnable examples live in examples/ — basic, supervision, registry, stream, forward, pool, pubsub, broker, message_bus, message_queue, and more. Run one with:
cargo run --example basicBombay builds on stable Rust (edition 2024, ≥ 1.85). The pinned toolchain lives in rust-toolchain.toml, so plain rustup and Nix resolve the same compiler.
nix develop # dev shell with the pinned toolchain (or use your own rustup stable)
cargo build
cargo run --example basiccargo nextest run # the whole workspace
cargo test --doc # doc-tests (nextest does not run these)
cargo test -p bombay_console # one crate
cargo test --test core_actor_id_bdd # one cucumber suiteOr run everything the CI gate runs in one shot:
nix flake check # build + clippy + fmt + audit + deny + nextest + doctest + actionlint
nix build .#coverage -L # llvm-cov HTML report -> ./result/html/index.htmlBehaviour is captured as Gherkin .feature files under tests/features/ and wired to the real code by cucumber runners in tests/ and each crate's tests/. Coverage is produced by cargo-llvm-cov through nix build .#coverage (a cargo-tarpaulin engine is also wired as a Linux opt-in via .#coverage-tarpaulin); the per-file baseline and gap triage are in docs/testing/coverage-baseline.md.
Dual-licensed under either of MIT or Apache-2.0, at your option, carrying kameo's upstream attribution (see NOTICE).