Почему этот дочерний процесс не запускается, когда я запускаю его родительский процесс?

Предположим, у меня есть следующая настройка дерева супервизора с одним родителем, начинающим ребенка, и ребенком, начинающим его внука:

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

Предположим, я выполняю следующие команды в терминале iex в следующем порядке:

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

Почему внучка BranchSupervisor не запускается? Когда я делаю Supervisor.which_children(cid), я получаю пустой список... Я думал, что BranchSupervisor#init вызывается после вызова NestedSupervisorTree.start_branch(2), за которым следует NestedSupervisorTree#start_link. Я также думал, что надзор в конце BranchSupervisor#init запустил детей...? Или это просто говорит вам, какой "тип детей" может наблюдать BranchSupervisor и "стратегия" для их контроля?

1 ответ

Решение

Когда вы установите strategy в :simple_one_for_oneСупервизор не запускает ни одного ребенка автоматически. Он принимает один элемент в списке детей, который служит шаблоном для вызова start_child потом. Вам нужно будет позвонить start_child самостоятельно, если вы хотите запустить дочерний процесс. Если вы хотите, чтобы только один ребенок был запущен, и вы хотите, чтобы это делалось автоматически, вы, вероятно, ищете :one_for_one стратегия.

Из документации руководителя:

:simple_one_for_one - похожий на :one_for_one но лучше подходит при динамическом прикреплении детей. Эта стратегия требует, чтобы в спецификации супервизора содержался только один дочерний элемент. Многие функции в этом модуле ведут себя немного иначе, когда используется эта стратегия.

а также

простой для одной спецификации может определить только один дочерний элемент, который работает как шаблон для того, когда мы вызываем start_child/2

Другие вопросы по тегам