Supervisor

The Supervisor module provides supervision trees for managing actor lifecycles. Supervisors monitor child actors and can restart them when they fail, implementing fault-tolerant patterns inspired by Erlang/OTP.

Supervision Trees

Supervisors form a hierarchy where each supervisor manages its children. When a child fails, the supervisor's restart strategy determines how to recover.

Restart Strategies

Supervisors support three restart strategies that determine what happens when a child fails:

:isolate
Only restart the failed child. Other children are unaffected. This is the default and most common strategy.
:all
Restart all children when one fails. Useful when children have interdependent state.
:cascade
Restart the failed child and all children started after it. Useful for dependencies where later children depend on earlier ones.

Child Specifications

Each child is specified as a record with the following fields:

# Child specification record
{
  handler: fn(msg, state) => new-state,  # Message handler function
  state: initial-state,                   # Initial state for the actor
  name: "worker-1"                       # Optional: name for the child
}

Supervisor API

Supervisor.start
Keyword -> List ChildSpec -> Int
Starts a supervisor with the given restart strategy and child specifications. Returns the supervisor ID.
handler = fn(-msg, state) => state + 1

children = [
  {handler: handler, state: 0, name: "worker-1"},
  {handler: handler, state: 0, name: "worker-2"}
]

sup = Supervisor.start :isolate children
Supervisor.stop
Int -> Unit
Stops the supervisor and all its child actors.
Supervisor.stop sup
Supervisor.children
Int -> List Int
Returns a list of all child actor IDs managed by the supervisor.
child-ids = Supervisor.children sup
println "Children: ${child-ids}"
Supervisor.child-count
Int -> Int
Returns the number of children managed by the supervisor.
Supervisor.is-running?
Int -> Bool
Returns true if the supervisor is currently running.

Error Types

type SupervisorError =
  | InvalidStrategy String
  | InvalidChildSpec String
  | StartFailed String
  | NotRunning

Complete Example

# Define a worker handler
worker-handler = fn(msg, state) =>
  match msg
    | :work -> state + 1
    | :reset -> 0
    | _ -> state

# Create child specifications
children = [
  {handler: worker-handler, state: 0, name: "worker-1"},
  {handler: worker-handler, state: 0, name: "worker-2"},
  {handler: worker-handler, state: 0, name: "worker-3"}
]

# Start supervisor with isolate strategy
sup = Supervisor.start :isolate children

# Get child actors and send them work
workers = Supervisor.children sup
workers |> List.each (fn(w) => w <- :work)

# Check status
println "Supervisor running: ${Supervisor.is-running? sup}"
println "Child count: ${Supervisor.child-count sup}"

# Cleanup
Supervisor.stop sup