ractor-supervisor
An OTP-style supervisor for the ractor framework—helping you build supervision trees in a straightforward, Rust-centric way.
Inspired by the Elixir/Erlang supervision concept, ractor-supervisor provides a robust mechanism for overseeing one or more child actors and automatically restarting them under configurable policies. If too many restarts happen in a brief time window—a "meltdown"—the supervisor itself shuts down abnormally, preventing errant restart loops.
Supervisor Types
This crate provides three types of supervisors, each designed for specific use cases:
1. Static Supervisor (Supervisor)
- Manages a fixed set of children defined at startup
- Supports all supervision strategies (OneForOne, OneForAll, RestForOne)
- Best for static actor hierarchies where child actors are known at startup
- Example: A web server with predefined worker pools, cache managers, and connection handlers
- See test examples
2. Dynamic Supervisor (DynamicSupervisor)
- Allows adding/removing children at runtime
- Uses OneForOne strategy only (each child managed independently)
- Optional
max_childrenlimit - Best for dynamic workloads where children are spawned/terminated on demand
- Example: A job queue processor that spawns worker actors based on load
- See test examples
3. Task Supervisor (TaskSupervisor)
- Specialized version of DynamicSupervisor for managing async tasks
- Wraps futures in actor tasks that can be supervised
- Simpler API focused on task execution rather than actor management
- Best for background jobs, periodic tasks, or any async work needing supervision
- Example: Scheduled jobs, background data processing, or cleanup tasks
- See test examples
Supervision Strategies
The strategy defines what happens when a child fails:
- OneForOne: Only the failing child is restarted.
- OneForAll: If any child fails, all children are stopped and restarted.
- RestForOne: The failing child and all subsequent children (in definition order) are stopped and restarted.
Strategies apply to all failure scenarios, including:
- Spawn errors (failures in
pre_start/post_start) - Runtime panics
- Normal and abnormal exits
Example: If spawning a child fails during pre_start, it will count as a restart and trigger strategy logic.
Common Features
Restart Policies
- Permanent: Always restart, no matter how the child exited.
- Transient: Restart only if the child exited abnormally (panic or error).
- Temporary: Never restart, regardless of exit reason.
Meltdown Logic
max_restartsandmax_seconds: The "time window" for meltdown counting. If more thanmax_restartsoccur withinmax_seconds, the supervisor shuts down abnormally (meltdown).restart_counter_reset_after: If the supervisor sees no failures for this many seconds, it clears its meltdown log and effectively "resets" the meltdown counters.
Child-Level Features
restart_counter_reset_after(per child): If a specific child remains up for that many seconds, its own failure count is reset to zero on the next failure.backoff_fn: An optional function to delay a child's restart. For instance, you might implement exponential backoff to prevent immediate thrashing restarts.
Important Requirements
-
Actor Names: Both supervisors and their child actors must have names set. These names are used for:
- Unique identification in the supervision tree
- Meltdown tracking and logging
- Global actor registry
-
Proper Spawning: When spawning supervisors or child actors, always use:
Supervisor::spawn_linkedorSupervisor::spawnfor static supervisorsDynamicSupervisor::spawn_linkedorDynamicSupervisor::spawnfor dynamic supervisors- Do NOT use the generic
Actor::spawn_linkeddirectly
Multi-Level Supervision Trees
Supervisors can manage other supervisors as children, forming a hierarchical or tree structure. This way, different subsystems can each have their own meltdown thresholds or strategies. A meltdown in one subtree doesn't necessarily mean the entire application must go down, unless the top-level supervisor is triggered.
For example:
Root Supervisor (Static, OneForOne)
├── API Supervisor (Static, OneForAll)
│ ├── HTTP Server
│ └── WebSocket Server
├── Worker Supervisor (Dynamic)
│ └── [Dynamic Worker Pool]
└── Task Supervisor
└── [Background Jobs]
Example Usage
Here's a complete example using a static supervisor:
use Actor;
use *;
use ;
use Instant;
use FutureExt;
// A minimal child actor that simply does some work in `handle`.
;
// A function to spawn the child actor. This will be used in ChildSpec::spawn_fn.
async
async
For more examples, see the test files: