Разрешение имен в дереве контроля - PullRequest
0 голосов
/ 10 мая 2019

Я пытаюсь разрешить GenServer, управляемый Приложением, по зарегистрированному имени в elixir 1.9. Вот пример кода:

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) по имени нельзя. Я понимаю способ запуска дочерних процессов , похоже, недавно изменился , что, похоже, вызвало некоторую путаницу. Что я делаю не так?

EDIT

Изменение функции config_spec на это, похоже, позволило ей работать:

  defp config_spec() do
    %{
      id: Experiment.Data,
      start: {
        Experiment.Data,
        :start_link,
        [
          "some data",
          [
            {:name, Experiment.Data}
          ]
        ]
      }
    }
  end

1 Ответ

1 голос
/ 10 мая 2019

GenServer.start_link хочет список ключевых слов для параметров или, другими словами, список из двух кортежей.[:name, Experiment.Data] - это список из двух атомов, поэтому он не вступает в силу.Вы можете написать его как [{:name, Experiment.Data}] или использовать специальный синтаксис для списков ключевых слов [name: Experiment.Data].

...