Reading — step 1 of 4
Learn
A supervisor is a process that monitors child processes and restarts them on failure. The cornerstone of Elixir's "let it crash" philosophy.
defmodule MyApp.Supervisor do
use Supervisor
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
end
def init(:ok) do
children = [
{Counter, 0},
{Cache, :cache_a},
{Worker, []},
]
Supervisor.init(children, strategy: :one_for_one)
end
end
Each child is {ModuleName, init_arg} — the supervisor calls ModuleName.start_link(init_arg).
Strategies:
:one_for_one— restart only the failed child:one_for_all— restart all children:rest_for_one— restart the failed child + all started after it
Restart options per-child (in the child's start_link or via child_spec):
:permanent— always restart (default for GenServer):temporary— never restart:transient— restart only on abnormal termination
max_restarts and max_seconds — if a child crashes too often, the supervisor itself terminates (preventing infinite restart loops).
Supervision tree:
App Supervisor (one_for_all)
├─ DB Supervisor (one_for_one)
│ ├─ Postgres Pool
│ └─ Read Replica Pool
├─ Web Supervisor
│ ├─ Endpoint
│ └─ WebSocket Manager
└─ Job Supervisor (one_for_one)
└─ Worker Pool
Failures in one branch don't necessarily take down others. The whole shape is declarative — change the tree, change the failure semantics.
The mantra: "don't write defensive code, write supervised code." When a process crashes, the supervisor restarts it from a clean state. This is faster, simpler, and more reliable than try/catch around every operation.
DynamicSupervisor — supervisors where children are added/removed at runtime (e.g., one process per active user session).
Application — the top-level supervisor + lifecycle hooks. Every Elixir release is an Application.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…