Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SpriteEngine Logo

Sprite Engine

A fault-tolerant actor runtime for Rust. Like React, but for concurrent systems.

On Crates

Crates.io Version Crates.io Total Downloads Crates.io Recent Downloads docs.rs

Rust 2021 License Apache 2.0 Build Passing Fault Tolerance 100% Recovery <50ns


⚡ What is Sprite?

Sprite is a Rust library for building fault-tolerant, concurrent actor systems with a clean, declarative API inspired by React.

Instead of writing complex supervision trees and manual error handling, you write actor components — pure setup closures that declare state, message handlers, and children. If an actor panics, Sprite automatically resurrects it in under 50 nanoseconds with its state intact.


🚀 Quick Start

use sprite_core::{Engine, Message};

fn main() {
    let engine = Engine::new();

    let counter = engine.spawn("counter", |ctx| {
        // Like React's useState — survives crashes
        let count = ctx.use_state("count", 0i64);

        ctx.on_message(move |msg| {
            if msg == "inc" {
                count.update(|c| c + 1);
                println!("count = {}", count.get());
            }
        });
    });

    counter.send(Message::text("inc"));
    counter.send(Message::text("inc"));
}

🧩 Core Concepts

Concept React Equivalent What it does
Engine createRoot The runtime that mounts and manages actors
engine.spawn(name, |ctx| { ... }) <Component /> Creates an actor from a setup closure
ctx.use_state(key, initial) useState Declares typed state that survives crashes
ctx.use_scratch(initial) useRef Ephemeral value wiped on recovery
ctx.on_message(|msg| { ... }) onClick / event handler Registers a message handler
ctx.on_panic(| | { ... }) componentDidCatch Runs after each panic recovery
ctx.on_mount(| | { ... }) useEffect([], ...) Runs once on first start
ctx.on_unmount(| | { ... }) cleanup function Runs on graceful shutdown
ctx.spawn(name, ...) child components Spawns nested actors
ctx.send_to(id, msg) props callback Sends a message to another actor
ctx.send_named(name, msg) Sends to a named actor
ctx.poll() Non-blocking message check
ctx.sleep(dur) Yield without blocking thread
Handle::send(msg) setState / props Sends a message to an actor
Handle::send_msg(any) Send any IntoMessage type
Handle::request(msg, timeout) fetch Request/response pattern

🔥 Fault Tolerance

     [ Panic in Actor ]
           │
           ▼
   catch_unwind catches it     (~0.05ms)
           │
           ▼
   Arena reset                  (~1ns)
           │
           ▼
   State already intact         (0ns — lives in shared store)
           │
           ▼
   Setup closure re-runs        (~1ms)
           │
           ▼
   Actor Fully Restored         (< 50ns for recovery core)

State created via use_state lives in a shared store outside the actor thread, so it survives panics automatically. The actor's scratch allocations (via bumpalo) are reset, but your data is safe.


🛡️ Circuit Breaker

If an actor panics more than 10 times in 5 seconds, Sprite trips a circuit breaker and halts it — preventing infinite crash loops.

engine.spawn("fragile", |ctx| {
    ctx.on_message(|_| panic!("always"));
    // After 10 recoveries, this actor stops.
});

📦 Installation

[dependencies]
sprite-core = { git = "https://github.com/dragprog/sprite-engine" }

🏗️ Advanced Examples

Actor Pool (load balancing)

use sprite_core::{Engine, Message, Pool};

let engine = Engine::new();
let pool = Pool::new(&engine, "worker", 4, |ctx| {
    ctx.on_message(|task| {
        println!("Worker {} processing: {:?}", ctx.id(), task);
    });
});

for i in 0..100 {
    pool.send(Message::int(i));
}

Broadcast

engine.broadcast(Message::text("shutdown"));

Named Actors

engine.spawn("logger", |ctx| {
    ctx.on_message(|msg| println!("{:?}", msg));
});

engine.send_named("logger", Message::text("hello"));
assert_eq!(engine.lookup("logger"), Some(id));

Timer

use sprite_core::Timer;
use std::time::Duration;

Timer::send_after(handle.tx.clone(), Duration::from_secs(5), Message::text("timeout"));

Builder API

use sprite_core::{Engine, ActorBuilder};

let handle = ActorBuilder::new("worker", |ctx| {
    ctx.on_message(|msg| { /* ... */ });
})
.arena_size(1024 * 128)
.max_recoveries(5)
.recovery_window(Duration::from_secs(10))
.spawn(&engine);

🧪 Running Tests

git clone https://github.com/dragprog/sprite-engine.git
cd sprite-engine
cargo test --workspace
cargo bench --bench recovery_speed
cargo bench --bench mailbox_throughput
cargo run --example counter
cargo run --example pool
cargo run --example broadcast

📊 Benchmarks

Benchmark Target
recovery_speed Panic → full restore
mailbox_throughput Messages / second

🤝 Contributing

  1. Fork the repo (git checkout -b feature/cool-thing).
  2. Keep the API surface minimal and ergonomic.
  3. Ensure tests pass (cargo test).
  4. Submit a PR with a concise breakdown.

📄 License

Distributed under the Apache License 2.0. See LICENSE for details.

About

Sprite Engine — A fault-tolerant actor runtime for Rust with a React-like API. Spawn concurrent actors that survive panics in under 50 nanoseconds, with state that persists across crashes automatically. Built on lock-free channels and zero-GC arena allocation. Think React hooks, but for resilient distributed systems.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages