2017-08-28 95 views
2

我一直在试图弄清楚如何在调用进程B中捕获或救援另一个进程A中的错误,该进程也杀死了进程A.如何通过在Elixir中调用进程来捕获或救援被调用进程的崩溃错误

这里是我的代码:

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块未得到执行。

我是否错过了对一个进程崩溃如何影响另一个的基本理解?只有当错误发生在同一过程中时,才尝试/赶上或尝试/解救工作?我是否必须监视其他进程并将其退出?

我会感谢您的帮助。

回答

1

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

+0

谢谢。所以如果我理解你,抛出/抛出错误和捕获/救出它必须发生在同一个过程中? –

+0

是的,必须在同一个进程代码 – Pouriya

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)是你想做这个动作和模式匹配只包含那些。

+0

谢谢。我[修改我的示例代码](https://gist.github.com/ahmadferdous/a5949e47b604dfda564b10c9461985df)。 B监视A并为'DOWN消息实现'handle_info'。但是,B不收到:DOWN消息。我仍在研究它。 –

相关问题