Use one_for_one leaf supervisors with tight intensity limits to contain Erlang crashes
Use one_for_one leaf supervisors with intensity 5 in 60 seconds to isolate worker crashes in Erlang OTP. A worked supervisor init shows how restart type, shutdown and strategy contain failures and when the supervisor intentionally escalates.
06 Oct 2025, 07:50 UTC

Contain a crashing worker without taking down its siblings
The practical decision for most production services is to put each independent worker behind a leaf supervisor configured with one_for_one and a tight restart intensity and period. A crash in one child restarts only that child, and if the child keeps crashing the supervisor stops itself after the limit is exceeded so the failure escalates to a parent that can make a broader decision.
one_for_one means the supervisor restarts only the child that exited. The intensity and period pair, written as {one_for_one, Intensity, Period}, caps how many restarts are allowed in a sliding window. Intensity is a count, period is seconds. When the cap is hit the supervisor terminates with reason shutdown and the failure propagates upward.
Mechanism in a worked supervisor configuration
A supervisor is declared in init/1. The return value is {ok, {SupFlags, ChildSpecs}}. SupFlags is {Strategy, Intensity, Period}. Each child spec describes how to start the child and how to restart it.
Example leaf supervisor for a long-lived gen_server:
-module(my_app_sup).-behaviour(supervisor).-export([start_link/0, init/1]).start_link()->supervisor:start_link({local, ?MODULE}, ?MODULE, []).init([])->SupFlags = #{strategy => one_for_one, intensity => 5, period => 60},ChildSpecs = [#{id => my_worker, start => {my_worker, start_link, []}, restart => permanent, shutdown => 5000, type => worker, modules => [my_worker]}],{ok, {SupFlags, ChildSpecs}}.The same configuration in the classic tuple form is:
{ok, {{one_for_one,5,60},[{my_worker, {my_worker,start_link,[]}, permanent,5000,worker,[my_worker]}]}}Fields to understand:
- strategy one_for_one isolates failures to the single child.
- intensity 5, period 60 allows at most 5 restarts of any child in 60 seconds. The counter is per supervisor, not per child.
- restart permanent means the child is always restarted on exit. transient restarts only on abnormal exit, temporary never restarts. Use transient for tasks that normally finish with normal.
- shutdown 5000 is the maximum time given to a child to stop gracefully during a planned supervisor shutdown. Worker type means the child is not a supervisor.
Hierarchical trees keep blast radius small. Top-level supervisors may use rest_for_one or one_for_all when ordering matters, but leaf supervisors that manage independent workers almost always use one_for_one.
Limits and common mistakes
Supervisors do not fix logic bugs. A worker that crashes repeatedly will exhaust the intensity window and cause the supervisor itself to terminate. That is intentional escalation, not a failure of supervision.
Using permanent restart for short-lived work creates restart loops. A task that is designed to start, do work, and exit normally should be transient or temporary, otherwise the supervisor will immediately restart it and consume intensity budget.
Large intensity values hide chronic instability. A high intensity with a long period delays detection of systemic problems such as a bad configuration or downstream dependency outage. Prefer a low intensity at the leaf and let a parent supervisor apply a broader policy.
Incorrect shutdown timeouts cause cascading delays on intentional shutdowns. If a child needs more than the shutdown value to flush state, increase the value or implement a proper terminate/2 callback. If the value is too large, stopping the application can stall for minutes.
Practical verification without claiming test results
To observe the policy, start the supervisor in an Erlang shell and inspect its children. The shell is run as a user with access to the node.
1> supervisor:which_children(my_app_sup).2> supervisor:count_children(my_app_sup).which_children returns a list of {Id, Pid, Type, Modules}. count_children reports specs, active, supervisors, workers.
To trigger a restart, obtain the worker pid from which_children and exit it. The supervisor should start a new pid for that id while other children remain unchanged. Repeated exits within the period should eventually cause the supervisor to terminate once intensity is exceeded, escalating to its parent.
Check the restart type by reading the child spec in the supervisor state or by code review. Verify shutdown behavior by stopping the supervisor with supervisor:terminate_child/2 and supervisor:delete_child/2 and observing that children receive shutdown signals within the configured timeout.
Risk: forcing crashes in production can exhaust resources and trigger escalation. Perform verification in an isolated development node and avoid kill signals on real traffic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.