Get your distributed joerl cluster running in 5 minutes!
In one terminal:
cd /path/to/joerl
cargo run --example epmd_serverYou should see:
========================================
joerl EPMD Server v0.3.0
========================================
INFO EPMD server listening on 127.0.0.1:4369
In a second terminal:
cargo run --example distributed_cluster -- node_a 5001Output:
========================================
Distributed Cluster Example
========================================
INFO [node_a] Registered with EPMD on port 5001
INFO [node_a] Spawning local actors...
INFO [node_a] Worker-1 started (pid: ...)
INFO [node_a] Worker-2 started (pid: ...)
INFO [node_a] Coordinator started (pid: ...)
In a third terminal:
cargo run --example distributed_cluster -- node_b 5002Node B will discover Node A automatically!
INFO [node_b] Registered with EPMD on port 5002
INFO [node_b] Discovered 1 peer(s): ["node_a"]
INFO [node_b] Active cluster: node_b + 1 peer(s)
Keep adding nodes:
# Terminal 4
cargo run --example distributed_cluster -- node_c 5003
# Terminal 5
cargo run --example distributed_cluster -- node_d 5004Each new node automatically discovers all existing nodes!
-
EPMD Server (Terminal 1)
- Maintains registry of all nodes
- Listens on port 4369 (Erlang standard)
- Removes dead nodes after timeout
-
Each Node (Terminals 2+)
- Registers with EPMD on startup
- Sends keep-alive every 20 seconds
- Queries EPMD every 5 seconds for peers
- Spawns local actors
-
Discovery Flow
Node → Register with EPMD Node → Start keep-alive loop Node → Query EPMD for peers EPMD → Returns list of all nodes Node → Discovers peers automatically
Create your own distributed node:
use joerl::epmd::{EpmdClient, DEFAULT_EPMD_PORT};
use joerl::ActorSystem;
#[tokio::main]
async fn main() {
// Create EPMD client
let epmd = EpmdClient::new(format!("127.0.0.1:{}", DEFAULT_EPMD_PORT));
// Register this node
let node_name = "my_custom_node";
let port = 6000;
epmd.register(node_name, "127.0.0.1", port)
.await
.expect("Failed to register");
// Start keep-alive
epmd.start_keep_alive_loop(
node_name.to_string(),
Duration::from_secs(20)
).await;
// Create actor system
let system = ActorSystem::new();
// Spawn actors...
// Discover peers...
// Send messages...
}-
Run EPMD as systemd service
sudo systemctl enable joerl-epmd sudo systemctl start joerl-epmd -
Use environment variables for configuration
let epmd_addr = env::var("EPMD_ADDRESS") .unwrap_or_else(|_| "127.0.0.1:4369".to_string());
-
Handle graceful shutdown
// On Ctrl+C epmd.unregister(node_name).await.ok();
# Check EPMD is running
netstat -an | grep 4369
# Try pinging EPMD
cargo run --example epmd_server &
# In Rust code:
epmd.ping().await.expect("EPMD not responding");Check registration worked:
let nodes = epmd.list_nodes().await?;
println!("Registered nodes: {:?}", nodes);Increase frequency:
// From 20s to 10s
epmd.start_keep_alive_loop(name, Duration::from_secs(10)).await;┌─────────────────┐
│ EPMD Server │
│ (Port 4369) │
│ │
│ Registry: │
│ - node_a:5001 │
│ - node_b:5002 │
│ - node_c:5003 │
└────────┬────────┘
│
┌────┴────┐
│ TCP │
│ Proto │
└────┬────┘
│
┌────┴────────────────────────┐
│ │
┌───▼────┐ ┌────────┐ ┌────────▼──┐
│ node_a │ │ node_b │ │ node_c │
│:5001 │ │:5002 │ │ :5003 │
│ │ │ │ │ │
│ Actors │ │ Actors │ │ Actors │
└────────┘ └────────┘ └───────────┘
✅ EPMD Server - Node registry and discovery
✅ EPMD Client - Registration and lookup API
✅ Protocol - Binary protocol (bincode)
✅ Keep-Alive - Automatic dead node removal
✅ Examples - Working cluster demo
The foundation for distributed clustering is complete! Next steps for full location transparency:
- Node Transport - TCP connections between nodes
- Remote Pids - Extend Pid with node information
- Message Routing - Transparent local/remote sending
- Serialization - Network-safe message format
- Connection Pooling - Reuse connections efficiently
See CLUSTERING.md for the full roadmap!
- Full Documentation: CLUSTERING.md
- Examples:
examples/distributed_cluster.rs - API Reference: Run
cargo doc --open - Tests:
cargo test epmd
Happy clustering! 🚀