No description
Find a file
Claude 5d8e413db2 fix: three SWIM notification bugs — death dissemination, piggyback notifications, partition recovery
Bug 1 (swim/node.rs): SwimProbe::check_suspicion_timeouts() calls
members.declare_dead() before translate_probe_actions() processes the
DeclareDead action. The second declare_dead() returned false (already dead),
so MembershipChanged{Dead} was never emitted and the death was never
enqueued for dissemination. Fix: remove the redundant declare_dead() call
in translate_probe_actions since the probe already performed the mutation.

Bug 2 (swim/node.rs): apply_membership_update() — which processes piggyback
on every ping/ack/ping_req — updated the internal member list but never
emitted NodeAction::MembershipChanged. This meant DistributedNode was blind
to all state transitions learned via gossip piggyback (e.g., a dead node
refuting via incarnation bump). Fix: return MembershipChanged actions from
apply_piggyback and propagate through handle_ping/handle_ack/handle_ping_req.

Bug 3 (node.rs): DistributedNode::handle_ping/handle_ack/handle_ping_req
never processed MembershipChanged actions from SwimNode — only tick() did.
Fix: extract process_membership_changes() helper and call it from all four
message paths (tick, handle_ping, handle_ack, handle_ping_req).

Additional fixes:
- registry.rs: add re_disseminate_all() for anti-entropy on partition heal
- node.rs: call re_disseminate_all on MemberState::Alive transitions so
  registry state accumulated during partition reaches recovering nodes
- cluster_scenarios: enable dead_reprobe in 10% message loss test, since
  correct death dissemination (now working) causes cascading false deaths
  without a recovery mechanism

Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
2026-02-13 08:39:14 +00:00
benches major feature update 2026-02-13 07:11:24 +00:00
crates fix: three SWIM notification bugs — death dissemination, piggyback notifications, partition recovery 2026-02-13 08:39:14 +00:00
docs distribution realization (#33) 2026-02-13 07:55:12 +00:00
examples feat: transport protocol (#27) 2026-02-09 19:05:37 +00:00
fuzz major feature update 2026-02-13 07:11:24 +00:00
src skeleton of wasm runner actors (#32) 2026-02-13 07:42:44 +00:00
tests distribution realization (#33) 2026-02-13 07:55:12 +00:00
tools feat: runtime dashboard and docs (#23) 2026-02-09 09:04:57 +00:00
.gitignore distribution realization (#33) 2026-02-13 07:55:12 +00:00
Cargo.lock distribution realization (#33) 2026-02-13 07:55:12 +00:00
Cargo.toml distribution realization (#33) 2026-02-13 07:55:12 +00:00
Dockerfile distribution realization (#33) 2026-02-13 07:55:12 +00:00
README.md distribution realization (#33) 2026-02-13 07:55:12 +00:00

swactor

Minimal actor runtime for Rust. Single-threaded or multi-threaded, with Python and WebAssembly bindings.

Quick Start

use swactor::actor::{ActorAddress, ActorInterface};
use swactor::runtime::{Ctx, Runtime, RuntimeConfig};

#[derive(Clone)]
struct Greet { name: String, reply_to: ActorAddress }

#[derive(Clone)]
struct Greeting(String);

struct Greeter;

impl ActorInterface for Greeter {
    type Incoming = Greet;
    type Response = Greeting;

    fn handle(&mut self, ctx: &Ctx, msg: Greet) {
        let _ = ctx.send(msg.reply_to, Greeting(format!("Hello, {}!", msg.name)));
    }
}

fn main() {
    let rt = Runtime::new(RuntimeConfig::default());
    let addr = rt.spawn(Greeter).unwrap();
    let inbox = rt.new_inbox::<Greeting>().unwrap();

    rt.send_to(addr, Greet { name: "world".into(), reply_to: *inbox.addr() }).unwrap();
    rt.tick();
    rt.tick();

    println!("{}", inbox.try_recv().unwrap().0); // "Hello, world!"
}

Features

Actor Model

Actors implement one trait (ActorInterface), receive one message type, and hold mutable state. No lifecycle hooks, no supervision trees, no async.

Every actor gets a 32-byte globally unique ActorAddress. The same ctx.send(addr, msg) call works whether the target is on the same worker, a different worker thread, an external inbox, or a remote process.

Single-threaded mode (rt.tick()) gives deterministic frame-level control. Multi-threaded mode (rt.run()) spawns OS threads with adaptive backoff.

See docs/runtime/actor-model.md and docs/runtime/runtime.md for the full model.

Transport

Pluggable cross-process messaging. User-provided codecs handle serialization (gRPC/protobuf, bincode, hand-rolled — no serde bounds imposed) and user-provided transports handle delivery (TCP, in-memory, gRPC channel).

cargo build --features transport
cargo run --example tcp_ping_pong --features transport -- receiver  # terminal 1
cargo run --example tcp_ping_pong --features transport -- sender    # terminal 2

See docs/distribution/transport.md for the routing chain, codec registry, and address resolution.

Runtime Dashboard

Live web dashboard for monitoring actors, message throughput, and mailbox depths. Supports trace recording and replay at configurable speed.

Includes hand-authored SVG diagrams (actor lifecycle, message lifecycle, tick cycle, transport routing) and generated diagrams from DOT sources (architecture, dataflow, type erasure).

See crates/runtime-dashboard/.

Language Bindings

Python — PyO3 via Maturin. Spawn actors from Python callables, pass dicts as messages, single-threaded or multi-threaded.

cd crates/swactor-python && maturin develop

Examples in examples/python/ (single-thread, async, Jupyter notebook).

WASM — wasm-bindgen. Runs single-threaded with deterministic addressing (no_random feature).

cd crates/swactor-wasm && wasm-pack build --target nodejs

Connectome Analysis

Structural analysis of the internal dependency graph.

  • depgraph (tools/depgraph/) — AST-based extraction of module dependencies, outputs GraphViz DOT
  • spectral (tools/spectral/) — Laplacian eigenvalue analysis, Connectome Complexity Index (CCI), coupling heatmaps, interactive HTML dashboard
cargo run --manifest-path tools/depgraph/Cargo.toml -- --src-dir src/ --output deps
python tools/spectral/spectral_analysis.py deps.dot

See docs/connectome/connectome.md for metric interpretation.

Building & Testing

cargo test                              # all tests
cargo test --features transport         # include transport tests
cargo run --example hello               # single actor example
cargo run --example ring                # 500-actor ring topology
cargo bench                             # benchmarks (criterion)

Feature Flags

Flag Default What it does
getrandom yes System RNG for actor addresses
no_random no Deterministic counter (WASM / reproducible tests)
transport no Pluggable remote messaging (codec + transport)
tracing no tracing instrumentation for runtime internals
serde no Serde derives for stats types
python no PyO3 bindings (cdylib wheel)

Documentation

Document Covers
Actor Model Traits, type erasure, addresses
Runtime Runtime, Ctx, Inbox, RuntimeHandle, stats
Worker Thread Tick phases, backoff, routing, full system topology
Channels HybridChannel, AddressMap, Placement
Transport Codec, Transport, remote messaging, address resolution
Distribution SWIM membership, Kademlia, NodeDriver
Connectome CCI metrics, spectral analysis interpretation
Dashboard Live web UI, trace recording, diagram index