我正在尝试通过elixir 1.9中的注册名称来解析由Application管理的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
钩子以检查它没有快死了,但这似乎没有被调用。我添加了日志记录行,向我显示该过程正在启动。我也尝试过使用注册名称调用该应用程序,这是可行的。但是,不按名称调用其子项(Experiment.Data
)。我了解子进程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
答案 0 :(得分:1)
GenServer.start_link
想要一个关键字列表作为选项,或者换句话说就是2元组的列表。 [:name, Experiment.Data]
是两个原子的列表,因此不会生效。您可以将其写为[{:name, Experiment.Data}]
或对关键字列表[name: Experiment.Data]
使用特殊语法。