A :one_for_one supervisor that runs under Lockstep's controller.
Builds on Lockstep.spawn_link/1 + Lockstep.flag(:trap_exit, true)
so child crashes are observed via {:EXIT, child, reason} and
restarts can be issued in-band with the rest of the test schedule.
Supported
- Strategy
:one_for_one. (Other strategies aren't modeled in v1.) - Restart options
:permanent,:transient,:temporary. max_restarts/max_secondsintensity. When exceeded the supervisor itself exits with reason:shutdown.start_link/2,which_children/1,count_children/1,start_child/2,terminate_child/2,restart_child/2.
Child specs
%{id: :counter, start: {Counter, :start_link, [42]}, restart: :permanent}Or the shorthand {Counter, 42}, which maps to
%{id: Counter, start: {Counter, :start_link, [42]}, restart: :permanent}.
Or the bare module Counter, which calls Counter.child_spec(:no_arg)
if exported, otherwise {Counter, :start_link, []}.
Caveats
Lockstep.Supervisordoes not invoketerminate/2callbacks on shutdown; seeLockstep.GenServerfor the same caveat.max_secondsuses Lockstep's virtual clock (Lockstep.now/0), so timing-based restart-intensity is reproducible across replays.
Summary
Functions
Count of currently-tracked child slots (including :undefined).
Build the supervisor-spec tuple returned from a use Supervisor
module's init/1 callback. Mirrors OTP Supervisor.init/2.
Restart a child whose pid is :undefined. Errors if the child is
already alive or doesn't exist.
Add a new child dynamically. Returns {:ok, pid} or {:error, reason}.
Start a supervisor. Two shapes
Terminate a running child by id. The slot is preserved with pid
:undefined so restart_child/2 can revive it.
List children: [{id, pid_or_:undefined, :worker, [module]}, ...].
Types
Functions
@spec count_children(pid()) :: non_neg_integer()
Count of currently-tracked child slots (including :undefined).
@spec init( [child_spec()], keyword() ) :: {:ok, {map(), [child_spec()]}}
Build the supervisor-spec tuple returned from a use Supervisor
module's init/1 callback. Mirrors OTP Supervisor.init/2.
def init(_arg) do
children = [...]
Lockstep.Supervisor.init(children, strategy: :one_for_one)
endReturns {:ok, {sup_flags, children}} where sup_flags carries
:strategy, :intensity (from :max_restarts), and :period
(from :max_seconds).
Restart a child whose pid is :undefined. Errors if the child is
already alive or doesn't exist.
@spec start_child(pid(), child_spec()) :: {:ok, pid()} | {:error, term()}
Add a new child dynamically. Returns {:ok, pid} or {:error, reason}.
@spec start_link([child_spec()] | module(), keyword() | any()) :: {:ok, pid()} | :ignore | {:error, term()}
Start a supervisor. Two shapes:
start_link(children_list, opts)-- children are a literal list of child specs.start_link(module, init_arg, opts)-- children are returned frommodule.init(init_arg), which must return{:ok, {sup_flags, child_specs}}(typically viaLockstep.Supervisor.init/2).
Options:
:strategy--:one_for_one(default; only one supported).:max_restarts-- default3.:max_seconds-- default5.
Terminate a running child by id. The slot is preserved with pid
:undefined so restart_child/2 can revive it.
@spec which_children(pid()) :: [child_info()]
List children: [{id, pid_or_:undefined, :worker, [module]}, ...].