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 |
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:
perform Actor.trap_exit(true)
behavior handle_info(msg: SystemMessage) { match msg { ExitSignal(actor, reason) => { perform IO.print("Actor exited: " + reason) } }}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 " + 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