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
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
- Elixir — GenServer — a process that holds state behind a contract.
- Elixir — Agent — the minimal state-holding process.
- Erlang — ets — in-memory tables for shared, fast reads.