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?
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