Elixir 中的动态主管规范
Posted
技术标签:
【中文标题】Elixir 中的动态主管规范【英文标题】:Dynamic Supervisor Spec in Elixir 【发布时间】:2016-06-24 17:09:09 【问题描述】:我创建了一个 GameSupervisor 监督模块,用于动态创建实例 GameServer (GenServer) 的子级。我可以看到在调用 GameSupervisor.start 函数时调用了 GameServer 的 start_link 方法,但它不会使 pid 保持活动状态。如果重启策略设置为临时,iex 中的 Process.alive?(pid) 总是返回 false。如果我将重启设置为瞬态或永久,当我在该 pid 上调用 GenServer.cast 时,它最终会再次调用 GameServer.start_link。
调用 start_child 是否不会自动将 pid 添加到监督树并使其保持活动状态?
GameSupervisor.ex
defmodule Prest.GameSupervisor do
alias Prest.GameServer
use Supervisor
@name :game_sup
def start_link() do
IO.puts "start link"
Supervisor.start_link(__MODULE__, [], [name: @name])
end
def start(uid) do
IO.puts "start bucket"
:ok, child = Supervisor.start_child(@name, [uid])
end
def init([]) do
IO.puts "init sup"
children = [
worker(GameServer, [], restart: :transient)
]
supervise(children, strategy: :simple_one_for_one)
end
end
GameServer.ex
defmodule Prest.GameServer do
use GenServer
# Client API
def start_link(uid) do
IO.puts "start game server"
GenServer.start_link(__MODULE__, uid, [])
end
def post(pid, event_id) do
:gen_server.cast(pid, :event, event_id)
end
# Server API
def init(uid) do
:ok, uid, [], []
end
def handle_cast(:event, event_id, state) do
#state = [event_id|state]
:noreply, "ok", state
end
end
谢谢
【问题讨论】:
【参考方案1】:据the docs:
:permanent
进程总是重新启动,即使它正常终止。
:transient
进程只有在异常终止时才会重新启动。
:temporary
进程永远不会重新启动。
您的GameServer
进程很可能由于某种原因而崩溃,并且主管正在按照其配置方式处理重启。
要对此进行调试,您需要检查您的日志(可能仅输出到终端)以了解进程崩溃的原因。如果您能够为其获取:ok, pid
,那么它可能不会在初始化时崩溃,这意味着handle_cast
、handle_call
或handle_info
子句是导致崩溃的原因。
没有代码,很难提供更具体的帮助。
在这种情况下,您的 handle_cast
的返回值看起来很糟糕。它should return:noreply, state
,但正在返回:noreply, "ok", state
。这通常是由于将handle_call
更改为handle_cast
并忘记删除回复值造成的。
【讨论】:
这是非常简单的代码 - 很难看出会出现什么错误。你有github链接吗?今晚我很高兴进行一些调试。 实际上,我确实看到了错误。handle_cast
的返回值错误。 elixir-lang.org/docs/stable/elixir/GenServer.html#c:handle_cast/…
具体来说,它应该返回:noreply, state
而不是:noreply, "ok", state
做到了。之前是 handle_call 但忘记更改参数。谢谢!以上是关于Elixir 中的动态主管规范的主要内容,如果未能解决你的问题,请参考以下文章
[Elixir009]像GenServer一样用behaviour来规范接口