在Elixir中运行时,从主管子项列表中添加/删除子项



我知道如何创建一个具有初始子级列表的主管。

defmodule TweetProcesser.DummySupervisor do
use Supervisor
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
end
@impl true
def init(:ok) do
children = [
Supervisor.child_spec({TweetProcesser.Worker, []}, id: :my_worker_1),
Supervisor.child_spec({TweetProcesser.Worker, []}, id: :my_worker_2),
Supervisor.child_spec({TweetProcesser.Worker, []}, id: :my_worker_3),
Supervisor.child_spec({TweetProcesser.Worker, []}, id: :my_worker_4),
Supervisor.child_spec({TweetProcesser.Worker, []}, id: :my_worker_5)
]
opts = [strategy: :one_for_one, name: TweetProcesser.WorkerSupervisor]
Supervisor.init(children, opts)
end
end

但是,我如何在运行时实现添加新子项或从该列表中删除子项的功能?通过这种方式,其他参与者可以在运行时调用这些函数,以便添加或删除子函数。

一种可能的方法是使用DynamicSupervisor,然后使用一个一次性的worker,为supervisor提供它的初始子级。

假设这是处理的基本代码

defmodule TweetProcesser.Worker do
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, [], [])
end
def init(_) do
{:ok, nil}
end
end
defmodule StartInitialChildren do
use Task
def start_link([]) do
Task.start_link(fn ->
[:my_worker_1, :my_worker_2, :my_worker_3, :my_worker_4, :my_worker_5]
|> Enum.each(fn id ->
spec = %{id: id, start: {TweetProcesser.Worker, :start_link, []}}
{:ok, _pid} = DynamicSupervisor.start_child(TweetProcesser.DummySupervisor, spec)
end)
end)
end
end

然后您可以将其添加到您的应用程序子中

defmodule MyApp.Application do
# ...
def start(_, _) do
def children = [
# ...
{DynamicSupervisor, name: TweetProcesser.DummySupervisor, strategy: :one_for_one},
StartInitialChildren
# ...
]
end
#...
end

实际情况是,你充满活力的上司将从没有孩子开始。

然后一次性任务将运行,并启动您希望它开始的5个孩子。

之后,您可以使用同一行代码来启动更多的孩子。

spec = %{id: some_id, start: {TweetProcesser.Worker, :start_link, []}}
DynamicSupervisor.start_child(TweetProcesser.DummySupervisor, spec)

当然,您可以通过定义辅助函数来使它变得更好,但要使基本功能继续运行,这应该很有用。

还要注意的是,正如这里的其他人所说,当你动态启动进程时,你可能应该避免将原子作为id,因为它们不会被完全清理,而且系统有整体限制。

最新更新