4

我创建了一个 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

游戏服务器.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

谢谢

4

1 回答 1

3

根据文档

  • 一个:permanent进程总是重新启动,即使它正常终止。
  • 一个:transient进程只有在它异常终止时才会重新启动。
  • :temporary进程永远不会重新启动。

很可能,您的GameServer进程由于某种原因而崩溃,并且主管正在按照配置的方式处理重新启动。

要对此进行调试,您需要检查日志(可能仅输出到终端)以查看进程崩溃的原因。如果你能得到一个{:ok, pid}for 它,那么它可能不会在 init 上崩溃,这意味着 a handle_cast, handle_call, orhandle_info子句是导致崩溃的原因。

没有代码,很难提供更具体的帮助。

handle_cast在这种情况下,您的返回值看起来很糟糕。它应该返回 {:noreply, state},但正在返回{:noreply, "ok", state}。这通常是由于将 a 更改handle_callhandle_cast并忘记删除回复值造成的。

于 2016-03-10T03:19:09.960 回答