joerl 🦀
An Erlang-inspired actor model library for Rust, named in tribute to Joe Armstrong, the creator of Erlang.
Features
- 🎠Actor Model: Lightweight actors that communicate via message passing
- 🤖 GenServer: Erlang's gen_server behavior with call/cast semantics
- 🌳 Supervision Trees: Robust error handling with configurable restart strategies
- 🔗 Links & Monitors: Actor relationships for failure detection and propagation
- 📬 Bounded Mailboxes: Backpressure support to prevent resource exhaustion
- âš¡ Async/Await: Built on tokio for excellent performance
- 🦀 Erlang Conventions: Familiar API for Erlang/OTP developers
Installation
Add this to your Cargo.toml:
[]
= "0.1"
= { = "1", = ["full"] }
= "0.1"
Quick Start
use ;
use async_trait;
// Define your actor
async
Core Concepts
Actors
Actors are the fundamental unit of computation. Each actor:
- Has a unique
Pid(Process ID) - Processes messages sequentially from its mailbox
- Can spawn other actors
- Can send messages to other actors
- Can link to and monitor other actors
Message Passing
Actors communicate by sending messages. Messages are type-erased using Box<dyn Any>:
actor_ref.send.await?;
actor_ref.send.await?;
Links and Monitors
Links create bidirectional relationships between actors. If one fails, both fail:
system.link?;
Monitors create unidirectional observation. The monitoring actor receives a DOWN signal when the monitored actor terminates:
let monitor_ref = actor_ref.monitor?;
Supervision Trees
Supervisors monitor child actors and restart them according to strategies:
use ;
let spec = new
.child
.child;
let supervisor = spawn_supervisor;
Restart Strategies:
OneForOne: Restart only the failed childOneForAll: Restart all children when one failsRestForOne: Restart the failed child and all children started after it
GenServer (Generic Server Behavior)
For structured stateful actors with synchronous call/reply and asynchronous cast semantics:
use ;
;
// Usage
let counter = spawn;
let value = counter.call.await?; // Synchronous
counter.cast.await?; // Asynchronous
Trapping Exits
Actors can trap exit signals to handle failures gracefully:
Erlang Terminology Mapping
|| Erlang | joerl | Description |
|--------|-------|-------------|
| spawn/1 | system.spawn(actor) | Spawn a new actor |
| gen_server:start_link/3 | gen_server::spawn(&system, server) | Spawn a gen_server |
| gen_server:call/2 | server_ref.call(request) | Synchronous call |
| gen_server:cast/2 | server_ref.cast(message) | Asynchronous cast |
| Pid | Pid | Process identifier |
| ! (send) | actor_ref.send(msg) | Send a message |
| link/1 | system.link(pid1, pid2) | Link two actors |
| monitor/2 | actor_ref.monitor(from) | Monitor an actor |
| process_flag(trap_exit, true) | ctx.trap_exit(true) | Trap exit signals |
| {'EXIT', Pid, Reason} | Signal::Exit { from, reason } | Exit signal |
| {'DOWN', Ref, process, Pid, Reason} | Signal::Down { reference, pid, reason } | Down signal |
Examples
See the examples/ directory for more examples:
counter.rs- Simple counter actorgen_server_counter.rs- GenServer (gen_server behavior) exampleping_pong.rs- Two actors communicatingsupervision_tree.rs- Supervision tree examplelink_monitor.rs- Links and monitors demonstrationremote_actors.rs- Distributed actors conceptual foundationdistributed_chat.rs- Multi-node chat system over TCP
Run examples with:
Distributed Actors Examples
The remote_actors example demonstrates the conceptual foundation for distributed systems:
This shows how multiple actor systems (nodes) can communicate through serializable messages, simulating the distributed nature of Erlang/OTP.
The distributed_chat example demonstrates a real distributed chat system using TCP:
# Terminal 1 - Start first node
# Terminal 2 - Start second node and connect to first
This example shows:
- TCP-based node-to-node communication
- Message serialization with JSON
- Connection management and routing
- Location-transparent messaging patterns
For detailed documentation on building distributed systems with joerl, see DISTRIBUTED.md.
Architecture
The library is organized into several modules:
actor- Core actor trait and contextsystem- Actor system runtime and registrymessage- Message types and signalsmailbox- Bounded mailbox implementationsupervisor- Supervision trees and restart strategieserror- Error types and resultspid- Process identifier
Testing
Run the test suite:
Check code coverage:
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Acknowledgments
This library is dedicated to the memory of Joe Armstrong (1950-2019), whose work on Erlang has inspired generations of developers to build robust, concurrent systems.