Supervision Trees
Fault Tolerance with Supervisors
Section titled “Fault Tolerance with Supervisors”Nulang implements Erlang/OTP-style supervision trees. A supervisor monitors child actors and applies a restart strategy when a child exits abnormally.
Creating a Supervisor
Section titled “Creating a Supervisor”let sup_id = perform Otp.create_supervisor("my_sup", 0)The second argument is the strategy:
| Value | Strategy | Behavior |
|---|---|---|
0 |
one_for_one |
Restart only the failed child |
1 |
one_for_all |
Restart all children on any failure |
2 |
rest_for_one |
Restart failed child + all children started after it |
3 |
simple_one_for_one |
All children are instances of a single template |
Adding Children
Section titled “Adding Children”Place an existing actor under supervision:
perform Otp.supervise_child(sup_id, worker_actor, 0)Child restart policies:
| Value | Policy | Description |
|---|---|---|
0 |
permanent |
Always restarted on exit |
1 |
temporary |
Never restarted |
2 |
transient |
Restarted only on abnormal exit |
3 |
respawn_on_node_loss |
Re-spawn the child on another node when its home node is confirmed gone (RFC 0014). Implies permanent semantics for the local exit protocol, plus shadow replication and directory registration. Only meaningful for durable children. |
Simple One-for-One Templates
Section titled “Simple One-for-One Templates”For simple_one_for_one supervisors, set a child template:
let sup = perform Otp.create_supervisor("pool", 3) // simple_one_for_one
// Register a spawnable behaviorperform Otp.set_template(sup, "PoolWorker")
// Dynamically start childrenlet child1 = perform Otp.start_child(sup)let child2 = perform Otp.start_child(sup)Linking and Monitoring
Section titled “Linking and Monitoring”Actors can be linked or monitored without full supervision:
// Link: abnormal exits propagate to the linked peerperform Actor.link(target)
// Unlink: remove the linkperform Actor.unlink(target)
// Monitor: receive a DOWN message when target exitsperform Actor.monitor(target)
// Demonitor: stop monitoringperform Actor.demonitor(target)Exit Trapping
Section titled “Exit Trapping”When trap_exit is enabled, linked peer exits arrive as system messages instead of killing the actor. Exit signals are delivered as messages; the actor handles them in its normal message loop.
perform Actor.trap_exit(true)Actor Exit Reasons
Section titled “Actor Exit Reasons”perform Actor.exit(0) // Normalperform Actor.exit(1) // Errorperform Actor.exit(2) // Kill (cannot be trapped by trap_exit)perform Actor.exit(99) // Custom reasonAbnormal exits (non-zero) propagate to linked peers. Kills (exit(2)) bypass trap_exit and always cascade.
Supervisor Exit Handling
Section titled “Supervisor Exit Handling”When a supervisor receives an exit signal from a child:
| Exit Reason | Action |
|---|---|
normal |
Child is removed, no restart |
kill |
Child is removed, no restart (already killed) |
error or custom |
Restart policy applied |
Supervisor actions cascade: if a supervisor restarts a child too many times in a short window, it escalates the failure to its supervisor — all the way up the tree.
Full Example
Section titled “Full Example”actor PoolWorker { state id: Int = 0
behavior init(worker_id: Int) { self.id = worker_id }
behavior process(task: String) { // Simulate work — may fail if task == "crash" { perform Actor.exit(1) } perform IO.print("Worker " + perform Int.to_string(self.id) + " processed: " + task) }}
// Main: Set up supervision treeactor Main { behavior run() { let sup = perform Otp.create_supervisor("pool", 3) // simple_one_for_one perform Otp.set_template(sup, "PoolWorker")
let w1 = perform Otp.start_child(sup) let w2 = perform Otp.start_child(sup)
send w1 process("hello") send w2 process("crash") // Worker 2 exits with error → restarted }}Actor Registry
Section titled “Actor Registry”Register actors by name for discovery:
perform Actor.register("logger")// ... elsewhere ...let logger = perform Actor.whereis("logger")Unregister when done:
perform Actor.unregister("logger")Scheduling Priority
Section titled “Scheduling Priority”Control an actor’s scheduling priority:
perform Actor.set_priority(0) // Highperform Actor.set_priority(1) // Normal (default)perform Actor.set_priority(2) // LowPriority affects scheduling order only — message order within a mailbox is always FIFO.
- Actor Stdlib Reference — full list of Actor.* built-in operations
- OTP Stdlib Reference — full list of Otp.* supervisor operations
- Distribution & Clustering — run supervised actors across nodes