Elixir GenServer.start_link抛出异常而不是返回元组

时间:2016-09-07 19:20:03

标签: elixir gen-server

我在GenServer玩了一下,我在实施自定义init回调时遇到了问题。

请考虑以下代码:

defmodule GenS do
  use GenServer

  def start_link(initial \\ 0) do
    GenServer.start_link(__MODULE__, initial)
  end

  def init(initial) do
    case initial do
      3 -> {:stop, "Can't initialise with 3"}
      _ -> {:ok, initial}
    end
  end
end

case GenS.start_link(3) do
  {:error, reason} -> IO.puts "Failed with #{reason}"
  {:ok,    _}      -> IO.puts "This has worked!"
end

IO.puts "I'm still alive!"

执行此代码时,我可以看到输出:

▶ elixir gens.ex
** (EXIT from #PID<0.46.0>) "Can't initialise with 3"

虽然我期待成功分支的类似输出(当作为参数传递的值不同于3时):

▶ elixir gens.ex
This has worked!
I'm still alive!

根据GenServer.start_link/3的文件:

  

如果init/1回调因原因而失败,则此函数返回{:error, reason}。否则,如果它返回{:stop, reason}:ignore,则该过程将终止,此函数将分别返回{:error, reason}:ignore

我希望能够返回元组,我可以啪嗒啪嗒地响起,但似乎并非如此。你有什么建议吗?

1 个答案:

答案 0 :(得分:1)

  

我希望能够返回元组,我可以啪的一声,但看起来并非如此。你有什么建议吗?

这里的问题是你正在链接到生成的进程,并且从{:stop, ...}返回init正在向调用进程发送一个退出信号,默认情况下会终止该调用进程。

您可以切换到使用GenServer.start(如果愿意,可以稍后手动链接进程),或者在开始GenS之前运行以下命令来捕获退出信号:

Process.flag(:trap_exit, true)

(请注意,当GenS死亡时,这会向调用进程发送一条消息,您可能要放弃该消息以防止浪费内存。)

在这两种情况下,我都得到以下输出:

Failed with Can't initialise with 3
I'm still alive!