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_casthandle_callhandle_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来规范接口

[Elixir007] on_definition规范函数定义时的各种潜规则

规范化管理的企业主管职务意味着什么?

测试主管如何规范公司的测试流程

Elixir - 基本主管设置崩溃而不是重新启动子进程

如何在 Elixir 主管中引用之前启动的进程