监督树中的名称解析
Name Resolution in Supervision Tree
我正在尝试通过 elixir 1.9 中的注册名称解析由应用程序管理的 GenServer。下面是一些示例代码:
defmodule Experiment do
use Application
def start(_type, _args) do
child_specs = [
config_spec()
]
Supervisor.start_link(child_specs, name: Experiment, strategy: :one_for_one)
end
defp config_spec() do
%{
id: Experiment.Data,
start: {
Experiment.Data,
:start_link,
[
"some data",
# set name of child process here
[:name, Experiment.Data]
]
}
}
end
end
defmodule Experiment.Data do
use GenServer
require Logger
def start_link(data, options \ []) do
Logger.info("starting with data '#{data}' and options [#{Enum.join(options, ", ")}]")
GenServer.start_link(__MODULE__, data, options)
end
@impl true
def init(data) do
Logger.info("starting")
{:ok, data}
end
@impl true
def handle_call(:data, _from, state) do
{:reply, state, state}
end
@impl true
def terminate(reason, _state) do
Logger.info("terminated: #{reason}")
end
def get_data(server) do
GenServer.call(server, :data)
end
end
我已经在 iex 中测试过了 (iex -S mix
):
iex(1)> {:ok, sup_pid} = Experiment.start(nil, nil)
10:45:36.914 [info] starting with data 'some data' and options [name, Elixir.Experiment.Data]
10:45:36.916 [info] starting
{:ok, #PID<0.189.0>}
iex(2)> Experiment.Data.get_data(Experiment.Data)
** (exit) exited in: GenServer.call(Experiment.Data, :data, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir) lib/gen_server.ex:979: GenServer.call/3
iex(2)> Experiment.Data.get_data(Elixir.Experiment.Data)
** (exit) exited in: GenServer.call(Experiment.Data, :data, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir) lib/gen_server.ex:979: GenServer.call/3
iex(2)> send(Experiment.Data, {self(), "hi"})
** (ArgumentError) argument error
:erlang.send(Experiment.Data, {#PID<0.187.0>, "hi"})
iex(2)> send(Experiment, {self(), "hi"})
{#PID<0.187.0>, "hi"}
iex(3)>
10:46:05.410 [error] Supervisor received unexpected message: {#PID<0.187.0>, "hi"}
这里让我感到困惑的是我试图用名字 Experiment.Data
注册 Experiment.Data
。但是当我尝试向名为 Experiment.Data
的进程发送消息时,找不到它。我添加了 terminate
钩子来检查它是否早死,但这似乎没有被调用。我添加了日志记录行,显示进程正在启动。我也试过通过注册名称调用应用程序,这很有效。然而,通过名称调用它的 child (Experiment.Data
) 不会。我了解 child 进程的启动方式 seems to have changed recently,这似乎引起了一些混乱。我做错了什么?
编辑
将 config_spec 函数更改为此似乎已允许它工作:
defp config_spec() do
%{
id: Experiment.Data,
start: {
Experiment.Data,
:start_link,
[
"some data",
[
{:name, Experiment.Data}
]
]
}
}
end
GenServer.start_link
想要选项的关键字列表,或者换句话说,一个二元组列表。 [:name, Experiment.Data]
是两个原子的列表,所以不生效。您可以将其写为 [{:name, Experiment.Data}]
或使用关键字列表的特殊语法 [name: Experiment.Data]
.
我正在尝试通过 elixir 1.9 中的注册名称解析由应用程序管理的 GenServer。下面是一些示例代码:
defmodule Experiment do
use Application
def start(_type, _args) do
child_specs = [
config_spec()
]
Supervisor.start_link(child_specs, name: Experiment, strategy: :one_for_one)
end
defp config_spec() do
%{
id: Experiment.Data,
start: {
Experiment.Data,
:start_link,
[
"some data",
# set name of child process here
[:name, Experiment.Data]
]
}
}
end
end
defmodule Experiment.Data do
use GenServer
require Logger
def start_link(data, options \ []) do
Logger.info("starting with data '#{data}' and options [#{Enum.join(options, ", ")}]")
GenServer.start_link(__MODULE__, data, options)
end
@impl true
def init(data) do
Logger.info("starting")
{:ok, data}
end
@impl true
def handle_call(:data, _from, state) do
{:reply, state, state}
end
@impl true
def terminate(reason, _state) do
Logger.info("terminated: #{reason}")
end
def get_data(server) do
GenServer.call(server, :data)
end
end
我已经在 iex 中测试过了 (iex -S mix
):
iex(1)> {:ok, sup_pid} = Experiment.start(nil, nil)
10:45:36.914 [info] starting with data 'some data' and options [name, Elixir.Experiment.Data]
10:45:36.916 [info] starting
{:ok, #PID<0.189.0>}
iex(2)> Experiment.Data.get_data(Experiment.Data)
** (exit) exited in: GenServer.call(Experiment.Data, :data, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir) lib/gen_server.ex:979: GenServer.call/3
iex(2)> Experiment.Data.get_data(Elixir.Experiment.Data)
** (exit) exited in: GenServer.call(Experiment.Data, :data, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir) lib/gen_server.ex:979: GenServer.call/3
iex(2)> send(Experiment.Data, {self(), "hi"})
** (ArgumentError) argument error
:erlang.send(Experiment.Data, {#PID<0.187.0>, "hi"})
iex(2)> send(Experiment, {self(), "hi"})
{#PID<0.187.0>, "hi"}
iex(3)>
10:46:05.410 [error] Supervisor received unexpected message: {#PID<0.187.0>, "hi"}
这里让我感到困惑的是我试图用名字 Experiment.Data
注册 Experiment.Data
。但是当我尝试向名为 Experiment.Data
的进程发送消息时,找不到它。我添加了 terminate
钩子来检查它是否早死,但这似乎没有被调用。我添加了日志记录行,显示进程正在启动。我也试过通过注册名称调用应用程序,这很有效。然而,通过名称调用它的 child (Experiment.Data
) 不会。我了解 child 进程的启动方式 seems to have changed recently,这似乎引起了一些混乱。我做错了什么?
编辑
将 config_spec 函数更改为此似乎已允许它工作:
defp config_spec() do
%{
id: Experiment.Data,
start: {
Experiment.Data,
:start_link,
[
"some data",
[
{:name, Experiment.Data}
]
]
}
}
end
GenServer.start_link
想要选项的关键字列表,或者换句话说,一个二元组列表。 [:name, Experiment.Data]
是两个原子的列表,所以不生效。您可以将其写为 [{:name, Experiment.Data}]
或使用关键字列表的特殊语法 [name: Experiment.Data]
.