在 OTP 中启动主管的童工时如何传递额外的参数?
How to pass in extra arguments when starting a child worker of a Supervisor in OTP?
假设我有以下设置:
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 的调用中注入 "extra arguments"?如果我删除 {_, wid} = Supervisor.start_child(__MODULE__, [3])
中的“3”,一切正常。这甚至是正确的做法吗?
这主要是一个学习练习。
这里的[3]
被附加到BranchSupervisor.init/1
中传递给worker
的args
,也就是[[2]]
,使得最后的参数[[2]] ++ [3]
=> [[2], 3]
。由于列表是两个元素长,Supervisor 然后调用 TreeWorker.start_link/2
就像 TreeWorker.start_link([2], 3)
,所以如果你想像这样接受两个参数,你只需要更改 start_link
以接受两个参数:
defmodule TreeWorker do
def start_link(arg1, arg2) do
# `arg1 == [2]` and `arg2 == 3` here
...
end
end
此行为记录在 Supervisor.start_child/2
:
In the case of :simple_one_for_one
, the child specification defined in
the supervisor is used and instead of a child_spec
, an arbitrary list
of terms is expected. The child process will then be started by
appending the given list to the existing function arguments in the
child specification.
假设我有以下设置:
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 的调用中注入 "extra arguments"?如果我删除 {_, wid} = Supervisor.start_child(__MODULE__, [3])
中的“3”,一切正常。这甚至是正确的做法吗?
这主要是一个学习练习。
这里的[3]
被附加到BranchSupervisor.init/1
中传递给worker
的args
,也就是[[2]]
,使得最后的参数[[2]] ++ [3]
=> [[2], 3]
。由于列表是两个元素长,Supervisor 然后调用 TreeWorker.start_link/2
就像 TreeWorker.start_link([2], 3)
,所以如果你想像这样接受两个参数,你只需要更改 start_link
以接受两个参数:
defmodule TreeWorker do
def start_link(arg1, arg2) do
# `arg1 == [2]` and `arg2 == 3` here
...
end
end
此行为记录在 Supervisor.start_child/2
:
In the case of
:simple_one_for_one
, the child specification defined in the supervisor is used and instead of achild_spec
, an arbitrary list of terms is expected. The child process will then be started by appending the given list to the existing function arguments in the child specification.