Supervision

Stages start as standard OTP actors, so a static_supervisor can hold them as children. For connections that survive restarts, give the stages names and declare the subscriptions on the builder. The stage then makes its declared subscriptions during startup. Startup fails for the checks the stage can make itself — a dead producer, a duplicate subscription, invalid demand values — and the supervisor retries. A refusal from the producer’s dispatcher arrives later, as an abnormal end of the subscription:

import gleam/otp/static_supervisor as supervisor
import gleam/otp/supervision

pub fn start_pipeline() {
  let counter_name = source.new_name("counter")

  supervisor.new(supervisor.RestForOne)
  |> supervisor.add(
    supervision.worker(fn() {
      counter_source() |> source.named(counter_name) |> source.start()
    }),
  )
  |> supervisor.add(
    supervision.worker(fn() {
      printer_sink()
      |> sink.subscribe(sluice.subscription(to: source.outlet_of(counter_name)))
      |> sink.start()
    }),
  )
  |> supervisor.start()
}

Use Permanent subscriptions with RestForOne. When a source stops, its consumers stop with it, the supervisor restarts the later stages in order, and each stage reconnects through the names.

A consumer supervisor joins the tree the same way. Give it a name with consumer_supervisor.new_name, declare its subscription on the builder with consumer_supervisor.subscribe, and add it as a worker child:

pub fn start_deliveries() {
  let orders_name = source.new_name("orders")
  let deliveries_name = consumer_supervisor.new_name("deliveries")

  supervisor.new(supervisor.RestForOne)
  |> supervisor.add(
    supervision.worker(fn() {
      order_source() |> source.named(orders_name) |> source.start()
    }),
  )
  |> supervisor.add(
    supervision.worker(fn() {
      consumer_supervisor.new(start_delivery)
      |> consumer_supervisor.named(deliveries_name)
      |> consumer_supervisor.subscribe(
        sluice.subscription(to: source.outlet_of(orders_name)),
      )
      |> consumer_supervisor.start()
    }),
  )
  |> supervisor.start()
}

The two supervisors do different jobs: the static supervisor restarts the stages of the pipeline, and the consumer supervisor restarts its own children, one for each event.

Search Document