如何在OTP中启动Supervisor的子工作者时传入额外的参数?

时间:2017-04-27 06:41:49

标签: elixir otp supervisor

假设我有以下设置:

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__, [3])
  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)
 iex> BranchSupervisor.start_worker
 # returns:
{:error,
 {:EXIT,
  {:undef,
   [{TreeWorker, :start_link, [[2], 3], []},
    {:supervisor, :do_start_child_i, 3, [file: 'supervisor.erl', line: 359]},
    {:supervisor, :handle_call, 3, [file: 'supervisor.erl', line: 384]},
    {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 629]},
    {:gen_server, :handle_msg, 5, [file: 'gen_server.erl', line: 661]},
    {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}}}

如何在对BranchSupervisor.start_worker的调用中注入“额外参数”?如果我删除了{_, wid} = Supervisor.start_child(__MODULE__, [3])中的“3”。这甚至是正确的做法吗?

这主要是一项学习练习。

1 个答案:

答案 0 :(得分:3)

此处的[3]附加到args worker BranchSupervisor.init/1 [[2]][[2]] ++ [3][[2], 3],最后的参数TreeWorker.start_link/2 } => TreeWorker.start_link([2], 3)。由于列表长度为两个元素,因此Supervisor将start_link调用defmodule TreeWorker do def start_link(arg1, arg2) do # `arg1 == [2]` and `arg2 == 3` here ... end end ,因此如果您想接受这样的两个参数,则只需要更改:simple_one_for_one以接受两个参数:

child_spec

Supervisor.start_child/2中记录了此行为:

  

在{{1}}的情况下,定义了子规范   使用主管而不是{{1}},任意列表   期望的条款。然后将启动子进程   将给定列表附加到现有函数参数中   儿童规范。