DynamicSupervisors 的工人名称
Worker names for DynamicSupervisors
大家好,
我是 elixir 的新手,对于在 elixir 中为 worker 设置 worker 名称和 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
普通主管一个模块叫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]}
]
但是当我告诉 Dynamic Supervisor 启动进程时
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]}]
worker的id似乎设置正确。有没有办法在通过 DynamicSupervisor 启动进程时设置名称?
已经非常感谢了!
里昂
看来您只是误解了 which_children/1
函数的返回值。它 returns 一个包含所有 children 实际上的信息的列表。
来自docs:
* id - it is always :undefined for dynamic supervisors
因此,您实际上正确地命名了您的进程。只是 Queue
模块的客户端代码不正确。如果您想访问这些功能,您应该修复您的功能 queue
enqueue
和 dequeue
以实际调用命名的 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
函数动态接收)。
大家好,
我是 elixir 的新手,对于在 elixir 中为 worker 设置 worker 名称和 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
普通主管一个模块叫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]}
]
但是当我告诉 Dynamic Supervisor 启动进程时
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]}]
worker的id似乎设置正确。有没有办法在通过 DynamicSupervisor 启动进程时设置名称?
已经非常感谢了!
里昂
看来您只是误解了 which_children/1
函数的返回值。它 returns 一个包含所有 children 实际上的信息的列表。
来自docs:
* id - it is always :undefined for dynamic supervisors
因此,您实际上正确地命名了您的进程。只是 Queue
模块的客户端代码不正确。如果您想访问这些功能,您应该修复您的功能 queue
enqueue
和 dequeue
以实际调用命名的 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
函数动态接收)。