1
votes

Suppose I have the following supervisor tree setup with one parent starting a child and the child starting its grandchild:

defmodule NestedSupervisorTree do
  # this will be the top line supervisor
  use Supervisor

  def start_link, do: Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)

  def init(:ok) do
    children = [
      supervisor(BranchSupervisor, [], restart: :temporary)
      #worker(TreeWorker, [], restart: :temporary)
    ]

    supervise(children, strategy: :simple_one_for_one)

  end

  def start_branch(args) do
    {_, branch_id} = Supervisor.start_child(__MODULE__, [args])
  end
end

defmodule BranchSupervisor do
  # this will be the top line supervisor
  use Supervisor

  def start_link(args), do: Supervisor.start_link(__MODULE__, [args], name: __MODULE__)

  def init(args) do
    IO.puts "branch init args:"
    IO.inspect args
    children = [
      worker(TreeWorker, [args], restart: :temporary)
    ]

    supervise(children, strategy: :simple_one_for_one)
  end

  def start_worker do
    {_, wid} = Supervisor.start_child(__MODULE__, [])
  end
end

defmodule TreeWorker do
  def start_link(args) do
    IO.puts "worker args:"
    IO.inspect args
    #IO.puts String.codepoints raw
    {:ok, spawn(fn -> loop end)}
  end

  def loop do
    receive do
      :stop -> :ok

      msg ->
        IO.inspect msg
        loop
    end
  end
end

Suppose I issue the following commands in the iex terminal in the following order:

 iex> {_, pid} = NestedSupervisorTree.start_link
 iex> {_, cid} = NestedSupervisorTree.start_branch(2)

Why doesn't BranchSupervisor's grandchild start? When I do Supervisor.which_children(cid) I get back an empty list... I thought BranchSupervisor#init gets called after calling NestedSupervisorTree.start_branch(2) followed by NestedSupervisorTree#start_link. I also thought the supervise at the end of BranchSupervisor#init started the children... ? Or does it just tell you which "type of children" BranchSupervisor can supervisor and the "strategy" for supervising them?

1

1 Answers

3
votes

When you set strategy to :simple_one_for_one, the Supervisor does not start any child automatically. It accepts one item in the children list which serves as a template for when you call start_child later. You'll need to call start_child yourself if you want to start the child process. If you only want one child to be started and you want that done automatically, you're probably looking for the :one_for_one strategy.

From the Supervisor documentation:

:simple_one_for_one - similar to :one_for_one but suits better when dynamically attaching children. This strategy requires the supervisor specification to contain only one child. Many functions in this module behave slightly differently when this strategy is used.

and

the simple one for one specification can define only one child which works as a template for when we call start_child/2