Current section

Files

Jump to
cmdc lib cmdc sub_agent supervisor.ex
Raw

lib/cmdc/sub_agent/supervisor.ex

defmodule CMDC.SubAgent.Supervisor do
@moduledoc """
子代理进程树动态监督者。
使用 `DynamicSupervisor` 管理子代理进程的生命周期。
每个子代理对应一个独立的 `CMDC.Agent` 进程,崩溃不传染父 Agent。
## 进程树位置
CMDC.SessionServer (:one_for_one)
├── CMDC.SubAgent.Supervisor ← 此模块
│ ├── CMDC.Agent (sub-coder)
│ ├── CMDC.Agent (sub-researcher)
│ └── ...
└── CMDC.Agent (main)
## 示例
{:ok, sup} = CMDC.SubAgent.Supervisor.start_link([])
{:ok, pid} = CMDC.SubAgent.Supervisor.start_child(sup, agent_opts)
:ok = CMDC.SubAgent.Supervisor.stop_child(sup, pid)
[pid1, pid2] = CMDC.SubAgent.Supervisor.list_children(sup)
"""
use DynamicSupervisor
# ==========================================================================
# Public API
# ==========================================================================
@doc "启动 SubAgent 动态监督者。"
@spec start_link(keyword()) :: Supervisor.on_start()
def start_link(opts) do
name = Keyword.get(opts, :name)
start_opts = if name, do: [name: name], else: []
DynamicSupervisor.start_link(__MODULE__, [], start_opts)
end
@doc """
在此监督者下启动一个子代理进程。
`agent_opts` 为传递给 `CMDC.Agent.start_link/1` 的选项列表,
必须包含 `:session_id` 字段。
返回 `{:ok, pid}``{:error, reason}`
"""
@spec start_child(pid() | atom(), keyword()) :: DynamicSupervisor.on_start_child()
def start_child(supervisor, agent_opts) when is_list(agent_opts) do
spec = %{
id: {CMDC.Agent, Keyword.fetch!(agent_opts, :session_id)},
start: {CMDC.Agent, :start_link, [agent_opts]},
restart: :temporary
}
DynamicSupervisor.start_child(supervisor, spec)
end
@doc """
停止指定 pid 的子代理进程。
进程不存在时返回 `:ok`(幂等)。
"""
@spec stop_child(pid() | atom(), pid()) :: :ok | {:error, :not_found}
def stop_child(supervisor, child_pid) when is_pid(child_pid) do
DynamicSupervisor.terminate_child(supervisor, child_pid)
end
@doc "列出此监督者下所有活跃子代理 pid。"
@spec list_children(pid() | atom()) :: [pid()]
def list_children(supervisor) do
DynamicSupervisor.which_children(supervisor)
|> Enum.flat_map(fn
{_, pid, :worker, _} when is_pid(pid) -> [pid]
_ -> []
end)
end
@doc "返回活跃子代理数量。"
@spec count(pid() | atom()) :: non_neg_integer()
def count(supervisor) do
DynamicSupervisor.count_children(supervisor).active
end
# ==========================================================================
# DynamicSupervisor Callbacks
# ==========================================================================
@impl true
def init(_args) do
DynamicSupervisor.init(strategy: :one_for_one)
end
end