如何通过在 Elixir 中调用进程来捕获或挽救被调用进程的崩溃错误
Posted
技术标签:
【中文标题】如何通过在 Elixir 中调用进程来捕获或挽救被调用进程的崩溃错误【英文标题】:How to catch or rescue called process' crash error by calling process in Elixir 【发布时间】:2018-02-05 23:48:02 【问题描述】:我一直试图弄清楚如何在调用进程 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 才有效吗?我是否必须监视其他进程并捕获其退出?
感谢您的帮助。
【问题讨论】:
【参考方案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) 是什么,并且模式匹配仅包含那些。
【讨论】:
谢谢。我modified my example code。 B 监视 A 并为 :DOWN 消息实现handle_info
。但是,B 没有收到 :DOWN 消息。我还在调查。【参考方案2】:
在 Erlang 生态系统中,只有在进程代码中引发异常时,您才可以使用 try-catch 捕获错误、退出和抛出,但如果进程因 atom normal
之外的任何原因退出,所有链接的进程都将收到退出信号,那些捕获退出的进程会以'EXIT', CrashedProcessPid, ReasonOfCrash
的形式将这个信号作为正常的erlang 消息接收。并且没有陷阱退出的其他进程将崩溃,原因为ReasonOfCrash
,并且与这些进程链接的其他进程将收到signalz等等。
【讨论】:
谢谢。所以如果我理解你,抛出/引发错误和捕获/救援它必须发生在同一个过程中?以上是关于如何通过在 Elixir 中调用进程来捕获或挽救被调用进程的崩溃错误的主要内容,如果未能解决你的问题,请参考以下文章
如何在Elixir或Erlang中在运行时动态创建和加载模块?