ash-flare
Fault-tolerant supervision trees for Rust with distributed capabilities inspired by Erlang/OTP. Build resilient systems that automatically recover from failures with supervisor trees, restart strategies, and distributed supervision.
Features
- 🌲 Supervision Trees: Hierarchical supervision with nested supervisors and workers
- 🔄 Restart Strategies:
OneForOne,OneForAll, andRestForOnestrategies - ⚡ Restart Policies:
Permanent,Temporary, andTransientrestart behaviors - 📊 Restart Intensity: Configurable restart limits with sliding time windows
- 🗂️ Stateful Workers: Optional shared in-memory KV store for workers (
StatefulSupervisorSpec) - 🌐 Distributed: Run supervisors across processes or machines via TCP/Unix sockets
- 🔌 Generic Workers: Trait-based worker system for any async workload
- 🛠️ Dynamic Management: Add/remove children at runtime
- 📝 Structured Logging: Built-in support for
slogstructured logging
Quick Start
Add to your Cargo.toml:
Basic Example
use ;
use async_trait;
// Define your worker
async
Restart Strategies
OneForOne
Restarts only the failed child (default):
use ;
let spec = new
.with_restart_strategy;
OneForAll
Restarts all children if any child fails:
let spec = new
.with_restart_strategy;
RestForOne
Restarts the failed child and all children started after it:
let spec = new
.with_restart_strategy;
Restart Policies
Control when a child should be restarted:
use RestartPolicy;
// Always restart (default)
Permanent
// Never restart
Temporary
// Restart only on abnormal termination
Transient
Nested Supervisors
Build hierarchical supervision trees:
let database_supervisor = new
.with_worker
.with_worker;
let app_supervisor = new
.with_supervisor
.with_worker;
let handle = start;
Restart Intensity
Configure maximum restart attempts within a time window:
use RestartIntensity;
let spec = new
.with_restart_intensity;
Stateful Workers with Shared Store
Use StatefulSupervisorSpec for workers that need to share state via an in-memory KV store:
use ;
use Arc;
// Create stateful supervisor (WorkerContext auto-initialized)
let spec = new
.with_worker;
let handle = start;
Or use the stateful_supervision_tree! macro for a more declarative approach:
use stateful_supervision_tree;
let spec = stateful_supervision_tree! ;
WorkerContext API:
get(key)- Retrieve a valueset(key, value)- Store a valuedelete(key)- Remove a keyupdate(key, fn)- Atomic update with a function
The store is process-local, concurrent-safe (backed by DashMap), and persists across worker restarts.
Dynamic Supervision
Add and remove children at runtime:
// Dynamically add a worker
let child_id = handle
.start_child
.await
.unwrap;
// Terminate a specific child
handle.terminate_child.await.unwrap;
// List all running children
let children = handle.which_children.await.unwrap;
Distributed Supervision
Run supervisors across processes or machines:
use ;
// Start supervisor server
let handle = start;
let server = new;
spawn;
// Connect from another process/machine
let remote = connect_tcp.await.unwrap;
let children = remote.which_children.await.unwrap;
remote.shutdown.await.unwrap;
Worker Lifecycle
Implement the Worker trait with optional lifecycle hooks:
use Worker;
use async_trait;
;
Error Handling
Workers return errors that trigger restart policies:
Structured Logging
Ash Flare uses slog for structured logging. To see logs, set up a global logger:
use ;
use Async;
use ;
Logs include structured data for easy filtering:
INFO server listening on tcp; address: "127.0.0.1:8080"
DEBUG child terminated; supervisor: "root", child: "worker-1", reason: Normal
ERROR restart intensity exceeded, shutting down; supervisor: "root"
Examples
Check the examples/ directory for more:
counter.rs- Basic supervisor with multiple workersdistributed.rs- Network-distributed supervisorssuper_tree.rs- Complex nested supervision treesinteractive_demo.rs- Interactive supervisor management
Run an example:
License
MIT License - see LICENSE file for details.
Acknowledgments
Inspired by Erlang/OTP's in some way.
Some code generated with the help of AI tools.