Build1 distinct publisher3 min readUpdated
A dev.to walkthrough reconstructs one-for-one supervision from BEAM primitives. The exercise separates the mechanism, links and exit signals, from the policy that decides what gets restarted.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Part 5 of a dev.to series on building distributed systems in Elixir rebuilds a supervisor by hand, with no GenServer and no OTP Supervisor, using only spawn/1, spawn_link/1, Process.flag(:trap_exit, true), send/2 and receive/1 [s1c1][s1c2]. The author is explicit that the point is not to replace OTP but to see the mechanism and the policy that an OTP supervisor provides [s1c3], and that division is the one worth keeping in your head the next time a node is churning through restarts.
The mechanism half is small. By default, a linked worker that crashes sends an exit signal that propagates and can terminate both processes [s1c4]. Set the trap_exit flag and the same signal arrives as an ordinary mailbox message, {:EXIT, pid, reason} [s1c5]. That is detection, and detection is only the beginning [s1c6]. Messages sent to a dead local PID do not bring the process back [s1c7], so something else has to decide what happens next.
The alternative the article rules out is polling with Process.alive?, for four reasons: detection is delayed until the next check, restart logic ends up scattered through the application, every worker has to be checked repeatedly, and a liveness check does not tell you why the worker stopped [s1c8]. Links and exit signals are already event-driven failure detection on the BEAM [s1c9].
The policy half is a list of responsibilities: trap exits, start and link both workers, record which PID maps to which logical worker name, wait for messages, restart a worker after an abnormal exit, leave healthy siblings running, and do not restart after a normal exit [s1c10]. The article calls that a minimal one-for-one restart strategy [s1c11].
The worker makes the policy input concrete. Worker.start/1 uses spawn_link/1, which starts the process and creates the link atomically [s1c12]. The loop carries a name and a processed-job count, replying {:done, name, value, new_count} to each job [s1c13]. A :crash message raises, which terminates the worker with an abnormal exit reason [s1c14]. A :stop message returns :ok, letting the function finish with reason :normal [s1c15]. The article states that this distinction determines whether the supervisor restarts the worker [s1c16]. In this implementation the exit reason is the whole of the policy input [s1d1], which is why a worker that exits cleanly will never come back and a worker that raises always will [s1d2].
One detail is easy to skim past: the supervisor itself is created with spawn/1 rather than spawn_link/1, because the caller running the demonstration is not part of the supervision relationship [s1c17]. Get that wrong in real code and your test harness becomes a supervision parent.
Worth noting what the published excerpt does not reach: it stops mid-sentence as the supervisor enters init/1 [s1c18], and the enumerated responsibilities contain no restart budget at all [s1d3]. A hand-rolled one-for-one loop with no intensity limit will restart a permanently broken child forever, which is exactly the failure mode teams misattribute to OTP.
Watch whether later parts of the series introduce restart intensity limits and strategies beyond one-for-one; the previous part covered process links [s1c19], so the ladder is being climbed in order.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The :crash branch raises an exception, terminating the worker with an abnormal exit reason, and the exit signal travels across the link to the supervisor.
The :stop branch returns :ok, letting the worker function finish normally so the worker exits with reason :normal.
The article states that the distinction between abnormal exit and :normal exit determines whether the supervisor restarts the worker.
Part 5 of the dev.to series 'Building Distributed Systems in Elixir' builds a small supervisor from scratch using spawn/1, spawn_link/1, Process.flag(:trap_exit, true), send/2 and receive/1.
The author states the goal is not to replace OTP but to understand the mechanism and policy that an OTP supervisor provides.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Self-demonstrating code, single source, incomplete
Nearly every claim is backed by code and prose inside the article itself, and the underlying statements about links, exit trapping and exit reasons are standard, checkable BEAM semantics rather than novel assertions. Evidence quality is capped by the cluster having exactly one publisher with no corroboration, and by the walkthrough being published without the restart loop that would demonstrate the policy end to end.
No adoption signal in supplied sources
The cluster contains a single tutorial with no release, deployment, usage disclosure, download, star count, benchmark or third-party uptake data. Nothing in the supplied material supports an adoption estimate for the pattern described, and inferring one from Elixir's general popularity would go beyond the sources.
Scope claimed is narrower than value delivered
The article makes no performance, superiority or production-readiness claims and explicitly disclaims replacing OTP, framing itself only as a mechanism-and-policy exercise. Its concrete content — exit-trapping order, PID-versus-logical-name identity, exit reason as the sole restart input — is slightly more useful than that modest framing advertises, so claims sit marginally below the evidence rather than above it.
Low commercial incentive, series-continuation interest
The item is a self-published instalment in a numbered tutorial series on a developer community platform, promoting no product, vendor, license or paid offering. The only visible incentive is audience and series momentum, which encourages instalment-shaped scope but creates little pressure to distort the technical claims.
Claims are low-risk but single-sourced
Confidence is moderate: the assertions are narrow, mostly reproduced as code, and concern well-established BEAM primitives, so misreading risk is low. It is held down by a one-publisher cluster, an article body that terminates before the restart implementation, and the complete absence of adoption evidence, which leaves one reality dimension unmeasurable.
build
The Elixir arbitrage roadmap that puts the Rust parser third, not first1 distinct publisher
build
Zenoh's put() returns before anyone can read it: a 3.9% stale-read rate in a tight loop1 distinct publisher
build
The payload is rebuilt every turn, so stop treating your prompt as a shipped artifact1 distinct publisher
build
Force the tool call, then hand Lightsail a long-lived key1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 17, 2026