Current section

Files

Jump to
gleam_otp src gleam otp supervisor.gleam
Raw

src/gleam/otp/supervisor.gleam

// // TODO: test
// import gleam/list
// import gleam/option.{None, Some}
// import gleam/otp/process.{ExitReason, Pid}
// // API
// pub opaque type Spec(argument) {
// Starting(pids: List(Pid), argument: argument, restarter: Restarter(argument))
// Failed(ExitReason)
// }
// pub opaque type ChildSpec(argument_in, argument_out) {
// ChildSpec(
// start: fn(argument_in) -> process.StartResult,
// update_argument: fn(argument_in, Pid) -> argument_out,
// )
// }
// type RestartInstruction {
// RestartAll
// RestartFrom(Pid)
// }
// type StartAcc(argument) {
// StartAcc(
// argument: argument,
// instruction: RestartInstruction,
// pids: List(Pid),
// restarter: fn(RestartInstruction) -> Result(StartAcc(argument), ExitReason),
// )
// }
// type Restarter(argument) =
// fn(RestartInstruction) -> Result(StartAcc(argument), ExitReason)
// type Child(argument) {
// Child(pid: Pid, argument: argument)
// }
// fn start_child(
// child_spec: ChildSpec(argument_in, argument_out),
// argument: argument_in,
// ) -> Result(Child(argument_out), ExitReason) {
// // Try and start the child
// try pid = child_spec.start(argument)
// // Merge the new child's pid into the argument to produce the new argument
// // used to start any remaining children.
// let argument = child_spec.update_argument(argument, pid)
// Ok(Child(pid: pid, argument: argument))
// }
// // TODO: more sophsiticated stopping of processes. i.e. give supervisors
// // more time to shut down.
// fn shutdown_child(child: Child(arg_2), _spec: ChildSpec(arg_1, arg_2)) -> Nil {
// process.send_exit(child.pid, process.Normal)
// }
// fn restart_child(
// argument: argument_in,
// instruction: RestartInstruction,
// child_spec: ChildSpec(argument_in, argument_out),
// child: Child(argument_out),
// ) -> Result(tuple(Child(argument_out), RestartInstruction), ExitReason) {
// let current = child.pid
// case instruction {
// // This child is older than the RestartFrom target, we don't need to
// // restart it
// RestartFrom(target) if target != current -> Ok(tuple(child, instruction))
// // This pid either is the cause of the problem, or we have the RestartAll
// // instruction. Either way it and its younger siblings need to be restarted.
// RestartAll -> {
// shutdown_child(child, child_spec)
// try child = start_child(child_spec, argument)
// Ok(tuple(child, RestartAll))
// }
// }
// }
// fn add_child_to_restarter(
// restarter: Restarter(argument_in),
// child_spec: ChildSpec(argument_in, argument_out),
// child: Child(argument_out),
// ) -> Restarter(argument_out) {
// fn(instr) {
// // Restart the older children. We use `try` to return early if the older
// // children failed to start
// try acc = restarter(instr)
// let argument = acc.argument
// // Restart the current child
// try pair = restart_child(argument, instr, child_spec, child)
// let tuple(child, instr) = pair
// // Create a new restarter for the next time the supervisor needs to restart
// let restarter = add_child_to_restarter(acc.restarter, child_spec, child)
// let pids = [child.pid, ..acc.pids]
// let acc = StartAcc(child.argument, instr, pids, restarter)
// Ok(acc)
// }
// }
// fn start_and_add_child(
// pids: List(Pid),
// argument: argument_0,
// restarter: Restarter(argument_0),
// child_spec: ChildSpec(argument_0, argument_1),
// ) -> Spec(argument_1) {
// case start_child(child_spec, argument) {
// Ok(child) -> {
// let pids = [child.pid, ..pids]
// let restarter = add_child_to_restarter(restarter, child_spec, child)
// Starting(pids: pids, argument: child.argument, restarter: restarter)
// }
// Error(reason) -> Failed(reason)
// }
// }
// pub fn add(
// spec: Spec(argument),
// child_spec: ChildSpec(argument, new_argument),
// ) -> Spec(new_argument) {
// case spec {
// // If one of the previous children has failed then we cannot continue
// Failed(fail) -> Failed(fail)
// // If everything is OK so far then we can add the child
// Starting(
// pids: pids,
// argument: argument,
// restarter: restarter,
// ) -> start_and_add_child(pids, argument, restarter, child_spec)
// }
// }
// // TODO: test
// // TODO: document
// pub fn worker_child(
// start: fn(argument) -> process.StartResult,
// ) -> ChildSpec(argument, argument) {
// ChildSpec(start: start, update_argument: fn(argument, _pid) { argument })
// }
// // TODO: test
// // TODO: document
// pub fn update_argument(
// child: ChildSpec(argument_a, argument_b),
// updater: fn(argument_a, Pid) -> argument_c,
// ) -> ChildSpec(argument_a, argument_c) {
// ChildSpec(start: child.start, update_argument: updater)
// }
// // Testing
// // pub fn start_child1(x: Nil) -> process.StartResult {
// // todo
// // }
// // pub fn start_child2(_older: Pid) -> process.StartResult {
// // todo
// // }
// // pub fn start_child3(_older: Pid) -> process.StartResult {
// // todo
// // }
// // pub fn init(spec) {
// // spec
// // |> add(
// // worker_child(start_child1)
// // |> update_argument(fn(_arg, pid) { pid }),
// // )
// // |> add(worker_child(start_child2))
// // |> add(worker_child(start_child3))
// // }