murmer 0.1.4

A distributed actor framework for Rust
Documentation

Typed, location-transparent actors that communicate through message passing. Whether an actor lives in the same process or on a remote node across the network, you interact with it through the same Endpoint<A> API.

                          ┌─ local ──→ Actor (in-memory, zero-copy)
Your Code → Endpoint<A> ──┤
                          └─ remote ─→ QUIC stream (bincode, encrypted) ──→ Actor (remote node)

Highlights

Location-transparent Same Endpoint<A> API whether the actor is local or on another node
Minimal boilerplate #[handlers] generates message structs, dispatch tables, and extension traits from plain method signatures
Networking included QUIC transport, TLS encryption, SWIM membership, mDNS discovery — configured, not hand-rolled
OTP-style supervision Restart policies (Temporary, Transient, Permanent) with limits and exponential backoff
Edge clients Lightweight MurmerClient connects to a cluster and calls public actors without joining it
Test without infra Spin up multi-node clusters in-memory from a single process

Quick Start

[dependencies]
murmer = "0.1"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

Define an actor:

use murmer::prelude::*;

#[derive(Debug)]
struct Counter;
struct CounterState { count: i64 }

impl Actor for Counter {
    type State = CounterState;
}

#[handlers]
impl Counter {
    #[handler]
    fn increment(&mut self, _ctx: &ActorContext<Self>, state: &mut CounterState, amount: i64) -> i64 {
        state.count += amount;
        state.count
    }

    #[handler]
    fn get_count(&mut self, _ctx: &ActorContext<Self>, state: &mut CounterState) -> i64 {
        state.count
    }
}

Use it:

#[tokio::main]
async fn main() {
    let system = System::local();
    let counter = system.start("counter/main", Counter, CounterState { count: 0 });

    let result = counter.increment(5).await.unwrap();
    assert_eq!(result, 5);

    // Lookup by label — works for local and remote actors
    let looked_up = system.lookup::<Counter>("counter/main").unwrap();
    let count = looked_up.get_count().await.unwrap();
    assert_eq!(count, 5);
}

Go distributed — swap one line, your actor code stays the same:

// Before: let system = System::local();
let system = System::clustered(config, TypeRegistry::from_auto(), SpawnRegistry::new()).await?;

// Everything else is identical
let counter = system.start("counter/main", Counter, CounterState { count: 0 });
let remote = system.lookup::<Counter>("counter/on-other-node").unwrap();
remote.get_count().await?;  // transparently serialized over QUIC

Edge Clients

Not everything that talks to your cluster needs to join it. Use MurmerClient to connect from a REST gateway, CLI tool, or test runner and call public actors directly:

use murmer::MurmerClient;

let client = MurmerClient::connect("10.0.0.5:9000".parse()?, "cluster-cookie").await?;
let ep = client.lookup::<UserService>("api/users").unwrap();
let user = ep.send(GetUser { id: 42 }).await?;
client.disconnect().await;

Mark actors as public on the server side with system.start_public():

// Visible to Edge clients
let api = system.start_public("api/users", UserService, state);

// Internal cluster actors — not visible to Edge clients (default)
let router = system.start("routing/shard", ShardRouter, state);

lookup_wait blocks until the actor appears — useful when connecting before the cluster has finished placing actors:

let ep = client
    .lookup_wait::<UserService>("api/users", Duration::from_secs(5))
    .await?;

See the Edge Clients chapter in the book for the full API, visibility model, and scalability details.

Documentation

Resource Description
The Murmer Book User guide: actors, discovery, supervision, clustering, macros, orchestration
API Reference Rustdoc on docs.rs
Examples Runnable demos: counter, cluster chat, orchestrator, edge client

Build & Test

cargo build
cargo nextest run
cargo clippy -- -D warnings

Why murmer?

I've spent years working with Elixir and the BEAM VM, and the actor model there is something I've grown deeply fond of — the simplicity of processes, message passing, and supervision just works. When I looked at bringing that experience to Rust, the existing frameworks were impressive but getting a basic actor up and running was complex, and adding remote communication was even more so.

Murmer is an experiment in answering: can you build a robust distributed actor system in Rust that's actually simple to use? The design draws from BEAM OTP, Akka's clustering, and Apple's Swift Distributed Actors — combined with Rust's performance and safety guarantees.

License

Licensed under either of

at your option.