actor-kit
A work-stealing actor runtime for Rust with OTP-style supervision trees, built for hosting 100,000+ actors per node (with modest per-actor mailboxes — see the capacity note in PERF-SLO.md) with efficient load balancing and bounded, backpressured mailboxes.
[]
= "0.1"
Quick example
use ;
use Arc;
Supervision (Erlang/OTP style, data-driven):
use ;
use Duration;
let mut tree = new;
let root = tree.root;
let child = tree.start_child_under?;
// ... on crash:
tree.handle_child_exit.await?;
// child is now Restarting; the supervisor counted it against max_restarts.
How it differs from task-per-actor runtimes
In ractor/kameo, each actor is a tokio task; scheduling is the async
runtime polling frames, and mailboxes are MPSC channels. actor-kit decouples
actors from tasks:
- Actors are registry entries (ID + state + bounded mailbox), not tasks.
- A fixed pool of OS workers pulls from a priority injector → local FIFO deque → global injector → steals from other workers (crossbeam deques), with spin/sleep backoff when idle.
- Mailboxes backpressure: lock-free
crossbeam_queue::ArrayQueue+ tokioSemaphore, backpressure flag at 80% of capacity (configurable).sendwaits,try_sendfails fast — a hot actor can never grow unbounded. - Supervision is data: OneForOne / OneForAll / RestForOne /
SimpleOneForOne, Permanent / Transient / Temporary restart policies,
max-restarts-per-window rate limiting, escalation actions
(Escalate / ShutdownNode / GiveUp), hierarchical
SupervisorTrees. You drive exits explicitly; there is no hidden per-supervisor task.
Honest comparison
| actor-kit | ractor | kameo | actix (actors) | |
|---|---|---|---|---|
| Execution model | fixed worker pool + work stealing | 1 tokio task/actor | 1 tokio task/actor | arbiter-thread actors |
| Supervision strategies | OneForOne/OneForAll/RestForOne/Simple + trees, restart window, escalation | one-for-one/all (supervisor actors) | experimental supervision | none (lifecycle hooks only) |
| Backpressure | bounded ArrayQueue + Semaphore, threshold flag | unbounded MPSC (bounded variant exists) | bounded, backpressured | bounded |
| Message typing | binary payloads + typed RPC (serde) | typed enums | typed messages | typed messages |
| Handler shape | sync state-machine step | async fn | async fn | async fn |
.await I/O mid-handler |
no (use RPC to an I/O actor) | yes | yes | yes |
| Panic containment | worker survives; actor → Failed, mailbox drained | task-level | task-level | arbiter-dependent |
When to prefer actor-kit: very many cheap actors, predictable per-actor memory, OTP fault-tolerance semantics, CPU-light handlers where task-per-actor overhead and unbounded mailboxes hurt.
When to prefer ractor/kameo: handlers that need to await I/O directly, rich typed message enums without a serde RPC layer, first-party ecosystem.
Feature flags
| feature | enables |
|---|---|
std (default) |
passthrough; the runtime is std-based |
serde |
typed RPC (rpc), serde impls, wire serialization (bincode) |
zero-copy |
rkyv zero-copy message path (zero_copy) |
unsafe-pool |
bump-allocator memory pool (memory_pool) |
full |
all of the above |
Unsafe-code policy
The crate carries #![deny(unsafe_code)]. The only unsafe code lives in
memory_pool behind the opt-in unsafe-pool feature: a raw-pointer bump
arena with a hand-rolled free list and manual Send/Sync impls, each with
SAFETY comments and documented invariants (module docs). Everything else —
scheduler, mailboxes, supervision, RPC, zero-copy serialization — is 100% safe.
Resource policy hook
Spawn/send admission is pluggable via the ResourcePolicy trait
(actor_kit::policy), replacing a hard dependency on any specific quota
system. Default is NoopPolicy (admit all):
use ResourcePolicy;
use Result;
;
Benchmarks
Three criterion suites: spawn_throughput, message_roundtrip,
steal_contention. Numbers are machine-dependent; run your own.
Deterministic gates: the tell hot path is pinned by an iai-callgrind
instruction gate (benches/iai_hot_path.rs — needs valgrind) and the
allocation profile by tests/zero_alloc_tell.rs (counting allocator, runs
on every cargo test). Every numeric claim is mapped to its proof artifact
in CLAIMS.md.
License
Dual-licensed under MIT or Apache-2.0, at your option.
Performance
Measured hot-path SLOs and allocation profile: PERF-SLO.md. Benchmarks run in CI (non-gating regression visibility against the saved ci baseline).