# `Lockstep.Supervisor`
[🔗](https://github.com/b-erdem/lockstep/blob/v0.1.0/lib/lockstep/supervisor.ex#L1)

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_seconds` intensity. 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.Supervisor` does not invoke `terminate/2` callbacks on
    shutdown; see `Lockstep.GenServer` for the same caveat.
  * `max_seconds` uses Lockstep's virtual clock (`Lockstep.now/0`),
    so timing-based restart-intensity is reproducible across replays.

# `child_id`

```elixir
@type child_id() :: any()
```

# `child_info`

```elixir
@type child_info() :: {child_id(), child_pid(), :worker | :supervisor, [module()]}
```

# `child_pid`

```elixir
@type child_pid() :: pid() | :undefined
```

# `child_spec`

```elixir
@type child_spec() :: %{
  :id =&gt; any(),
  :start =&gt; {module(), atom(), [any()]},
  optional(:restart) =&gt; :permanent | :transient | :temporary
}
```

# `count_children`

```elixir
@spec count_children(pid()) :: non_neg_integer()
```

Count of currently-tracked child slots (including :undefined).

# `init`

```elixir
@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)
    end

Returns `{:ok, {sup_flags, children}}` where `sup_flags` carries
`:strategy`, `:intensity` (from `:max_restarts`), and `:period`
(from `:max_seconds`).

# `restart_child`

```elixir
@spec restart_child(pid(), child_id()) :: {:ok, pid()} | {:error, term()}
```

Restart a child whose pid is `:undefined`. Errors if the child is
already alive or doesn't exist.

# `start_child`

```elixir
@spec start_child(pid(), child_spec()) :: {:ok, pid()} | {:error, term()}
```

Add a new child dynamically. Returns `{:ok, pid}` or `{:error, reason}`.

# `start_link`

```elixir
@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
    from `module.init(init_arg)`, which must return
    `{:ok, {sup_flags, child_specs}}` (typically via
    `Lockstep.Supervisor.init/2`).

Options:

  * `:strategy` -- `:one_for_one` (default; only one supported).
  * `:max_restarts` -- default `3`.
  * `:max_seconds` -- default `5`.

# `start_link`

```elixir
@spec start_link(module(), any(), keyword()) ::
  {:ok, pid()} | :ignore | {:error, term()}
```

# `terminate_child`

```elixir
@spec terminate_child(pid(), child_id()) :: :ok | {:error, :not_found}
```

Terminate a running child by id. The slot is preserved with pid
`:undefined` so `restart_child/2` can revive it.

# `which_children`

```elixir
@spec which_children(pid()) :: [child_info()]
```

List children: `[{id, pid_or_:undefined, :worker, [module]}, ...]`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
