jonnifyelixir
F5 / F5.06 / supervision

F5.06 · part 3 of 3

Supervision

A process that holds state will eventually meet a bug or a bad message and crash. The BEAM answer is not to wrap every line in defensive code but to let it crash and put a supervisor above it. When the engine dies, the supervisor starts a fresh one; init/1 folds the event log again, and the state is back. This is exactly why the F5.05 fold matters: because the log is the source of truth and replay is deterministic, a restart loses nothing. A strategy of :one_for_one restarts only the child that failed, and :permanent means it is always brought back.

Crash, restart, replay — a full cycle. Select a step to see what happens to the engine and its state.

The crash-restart cycle

Start with the engine running and holding state. A bad message crashes it — the process stops, and its in-memory state is gone. The supervisor notices and starts a fresh engine, whose init folds the log and rebuilds the state. The snapshot was disposable; the log was not. Select a step.

Crash, restart, replay · select a step

SUPERVISOR one_for_one · restart live holds state crash down state lost restart + replay live state replayed

step: running

what happens: engine holds the folded state

Recovery is replay, not repair. Keep the log and a crash costs you nothing but the moment it took to fold it again.

In code

A small supervision tree. The application starts a supervisor whose one child is the engine, handed its event log. :one_for_one restarts only the engine if it falls over, and on restart init folds the log again — the state rebuilds itself from the record.

defmodule Portal.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      {Portal.Engine, load_events()}    # the engine, started with its event log
    ]
    # one_for_one: if a child crashes, restart only that child
    opts = [strategy: :one_for_one, name: Portal.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

# when Portal.Engine crashes, the supervisor starts a fresh one;
# init/1 folds the log again, so the state is rebuilt — the log is the source of truth.

let it crash

Instead of defending every line, let a broken process die and have a supervisor replace it.

restart replays

A fresh engine's init folds the log, so the state returns on its own.

That closes F5.06: a GenServer owns the folded state, and a supervisor keeps it alive by replaying the log on restart. The next module, F5.07 — Pragmatic testing, tests the pure core and the engine boundary. Back to the module overview or the chapter.

References

Primary sources for this lesson, and where it connects in the course.

Sources

Related in this course