【问题标题】:Worker names for DynamicSupervisors动态主管的工作人员名称
【发布时间】:2020-12-05 02:13:01
【问题描述】:

大家好,

我对 elixir 有点陌生,并且在为 elixir 中的工人设置工人姓名和 ID 时非常迷茫,我希望有人可以帮助我。

我的申请文件

defmodule Squareup.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    children = [
      # Starts a worker by calling: Squareup.Worker.start_link(arg)
      # {Squareup.Worker, arg}
      Journey,
      Squareup.JourneySupervisor,
      {Squareup.DynamicJourneySupervisor, strategy: :one_for_one, name: Squareup.DynamicJourneySupervisor}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Squareup.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

所以我启动了 2 个主管,一个是常规的,一个是动态的:

普通的:

defmodule Squareup.JourneySupervisor do

  use Supervisor

  def start_link(opts) do
    Supervisor.start_link(__MODULE__, opts, name: :my_test_123)
  end

  @impl true
  def init(_init_arg) do
    children = [
      # Starts a worker by calling: Squareup.Worker.start_link(arg)
      # {Squareup.Worker, arg}
      {Queue, [:child_one]},
      {Queue, [:child_two]},
    ]
    Supervisor.init(children, strategy: :one_for_one)
  end

  def child_spec(opts) do
    %{
      id: :my_test_123s,
      start: {__MODULE__, :start_link, [opts]},
      shutdown: 5_000,
      restart: :permanent,
      type: :supervisor
    }
  end
end

动态的人:

defmodule Squareup.DynamicJourneySupervisor do
  use DynamicSupervisor

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  def start_child(init_args) do
    # If MyWorker is not using the new child specs, we need to pass a map:
    # spec = %{id: MyWorker, start: {MyWorker, :start_link, [foo, bar, baz]}}
    spec = {Queue, init_args}
    DynamicSupervisor.start_child(__MODULE__, spec)
  end

  @impl true
  def init(init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end
end

普通的supervisor一个模块叫Queue

defmodule Queue do
  require Logger
  use GenServer

  ### GenServer API
  def init(state), do: {:ok, state}
  def handle_call(:dequeue, _from, [value | state]) do {:reply, value, state} end
  def handle_call(:dequeue, _from, []), do: {:reply, nil, []}
  def handle_call(:queue, _from, state), do: {:reply, state, state}
  def handle_cast({:enqueue, value}, state) do {:noreply, state ++ [value]} end

  ### Client API / Helper functions

  def start_link(state \\ []) do
    Logger.info("Initializing queue with state:")
    Logger.info(inspect(state))
    GenServer.start_link(__MODULE__, state, name: List.first(state))
  end

  def child_spec(opts) do
    Logger.info("Initializing child_spec:")
    Logger.info(inspect(opts))
    %{
      id: List.first(opts),
      start: {__MODULE__, :start_link, [opts]},
      shutdown: 5_000,
      restart: :permanent,
      type: :worker
    }
  end

  def queue, do: GenServer.call(__MODULE__, :queue)
  def enqueue(value), do: GenServer.cast(__MODULE__, {:enqueue, value})
  def dequeue, do: GenServer.call(__MODULE__, :dequeue)
end

当我启动应用程序时,我会这样做:

12:55:45.744 [info]  Initializing child_spec:
12:55:45.749 [info]  [:child_one]
12:55:45.749 [info]  Initializing child_spec:
12:55:45.749 [info]  [:child_two]
12:55:45.749 [info]  Initializing queue with state:
12:55:45.749 [info]  [:child_one]
12:55:45.749 [info]  Initializing queue with state:
12:55:45.749 [info]  [:child_two]

iex(4)> Supervisor.which_children(:my_test_123)
[
  {:child_two, #PID<0.218.0>, :worker, [Queue]},
  {:child_one, #PID<0.217.0>, :worker, [Queue]}
]

但是当我告诉动态主管启动进程时

Squareup.DynamicJourneySupervisor.start_child([:my_dyname])
12:56:07.329 [info]  Initializing child_spec:
12:56:07.329 [info]  [:my_dyname]
12:56:07.330 [info]  Initializing queue with state:
12:56:07.330 [info]  [:my_dyname]

查找工人姓名,他们总是:undefined

iex(5)> Supervisor.which_children(Squareup.DynamicJourneySupervisor)
[{:undefined, #PID<0.224.0>, :worker, [Queue]}]

工人的 id 似乎设置正确。有没有办法在通过 DynamicSupervisor 启动进程时设置名称?

提前非常感谢!

里昂

【问题讨论】:

    标签: elixir


    【解决方案1】:

    看来您只是误解了which_children/1 函数的返回值。它实际上返回一个包含所有孩子信息的列表。

    来自docs

    * id - it is always :undefined for dynamic supervisors
    

    因此,您实际上正确地命名了您的流程。只是 Queue 模块的客户端代码不正确。如果你想访问它们,你应该修复你的函数 queue enqueuedequeue 以实际调用命名的 GenServer。

    我的意思是它们应该看起来像这样:

      def queue(name \\ __MODULE__), do: GenServer.call(name, :queue)
      def enqueue(name \\ __MODULE__, value), do: GenServer.cast(name, {:enqueue, value})
      def dequeue(name \\ __MODULE__), do: GenServer.call(name, :dequeue)
    

    这样GenServer.call/2 将始终调用命名的GenServers。您也可以不通过名称而是通过pids 访问它们(如果需要,您实际上可以从which_children/1 函数动态接收)。

    【讨论】:

    • 是的,你说得对,我很傻。它确实只是在文档中。非常感谢,也非常感谢队列模块修复!
    猜你喜欢
    • 2016-08-16
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多