如何通过调用Elixir

时间:2017-08-28 16:29:34

标签: erlang elixir otp

我一直在试图弄清楚如何在调用进程B中捕获或挽救另一个也杀死进程A的进程A中的错误。

这是我的代码:

defmodule A do
  def start_link do
    GenServer.start_link(__MODULE__, :ok, name: :A)
  end

  def fun(fun_loving_person) do
    GenServer.call(fun_loving_person, :have_fun)
  end

  def init(:ok) do
    {:ok, %{}}
  end

  def handle_call(:have_fun, _from, state) do
    raise "TooMuchFun"
    {:reply, :ok, state}
  end
end

defmodule B do
  def start_link do
    GenServer.start_link(__MODULE__, :ok, name: :B)
  end

  def spread_fun(fun_seeker) do
    GenServer.call(:B, {:spread_fun, fun_seeker})
  end

  def init(:ok) do
    {:ok, %{}}
  end

  def handle_call({:spread_fun, fun_seeker}, _from, state) do
    result = A.fun(fun_seeker)
    {:reply, result, state}
  rescue
    RuntimeError -> IO.puts "Too much fun rescued"
    {:reply, :error, state}
  end
end

{:ok, a} = A.start_link
{:ok, _b} = B.start_link
result = B.spread_fun(a)
IO.puts "#{inspect result}"

在模块B的handle_call函数中,我调用了模块A的函数,如果进程rescue出现任何问题,它会:A阻塞。引发了错误,但rescue块未执行。

我是否错过了对一个进程崩溃如何影响另一个进程的基本理解?只有在同一进程中发生错误时,try / catch或try / rescue是否有效?我是否必须监控其他进程并将其退出?

我将非常感谢你的帮助。

2 个答案:

答案 0 :(得分:1)

在Erlang生态系统中,只有在进程代码中引发异常时才能使用try-catch捕获错误,退出和抛出,但如果进程以除原子normal之外的任何原因退出,则所有链接进程将接收退出信号,那些传输退出的进程将以{'EXIT', CrashedProcessPid, ReasonOfCrash}的形式接收此信号作为正常的erlang消息。并且没有陷阱退出的另一个进程将因原因ReasonOfCrash而崩溃,并且与这些进程链接的其他进程将接收signalz等等。

答案 1 :(得分:1)

您可以通过让另一个进程监控此过程来完成您喜欢的任务。查看Process.monitor的文档:https://hexdocs.pm/elixir/Process.html#monitor/1

基本上,监控过程需要处理崩溃时生成的关闭消息的信息:

handle_info({:DOWN, ref, :process, object, reason}, state) do
  # do something interesting here ...
end

请记住,您需要弄清楚reason(s)您想要执行此操作和模式匹配的内容仅包含这些内容。