Erlang gen_server:如何捕获错误?

Posted

技术标签:

【中文标题】Erlang gen_server:如何捕获错误?【英文标题】:Erlang gen_server: How to catch Errors? 【发布时间】:2019-07-17 09:12:53 【问题描述】:

我是 Erlang 开发的新手,我对进程关系感兴趣。

如果我们将两个进程 P1 和 P2 与 process_flag(trap_exit, true) 链接并使用像 Pid ! msgreceive .. after .. end 这样的构造 - 有可能通过第二个进程 P2 捕获像 badarith 这样的 P1 错误。

但是如果我们使用与 P2 链接的 gen_server 进程 P1 , - P1 在 P2 失败后终止。

那么,如何使用 gen_server 捕获 exit() 错误?

提前致谢!

附:测试代码。

P1:

-module(test1).
-compile(export_all).
-behaviour(gen_server).

start() ->
  gen_server:start_link(local, ?MODULE, ?MODULE, [], []).

init([]) -> Link = self(),
            spawn(fun() ->
              process_flag(trap_exit, true),
              link(Link),
              test2:start(Link)
            end),
            ok, "lol".

handle_call(stop, From, State) ->
  io:fwrite("Stop from ~p. State = ~p~n",[From, State]),
  stop, normal, "stopped", State;

handle_call(MSG, From, State) ->
  io:fwrite("MSG ~p from ~p. State = ~p~n",[MSG, From, State]),
  reply, "okay", State.

handle_info(Info, State) -> io:fwrite("Info message ~p. State = ~p~n",[Info, State]), noreply, State.

terminate(Reason, State) -> io:fwrite("Reason ~p. State ~p~n",[Reason, State]), ok.

P2:

-module(test2).
-compile(export_all).

start(Mod) ->
  io:fwrite("test2: Im starting with Pid=~p~n",[self()]),
  receiver(Mod).

receiver(Mod)->
  receive
    stop ->
      Mod ! goodbye,
      io:fwrite("Pid: I exit~n"),
      exit(badarith);
    X ->
      io:fwrite("Pid: I received ~p~n",[X])
  end.

结果:test2 以 badarith 退出后,test1 进程失败。

38> 
38> c(test1).                    
test1.erl:2: Warning: export_all flag enabled - all functions will be exported
ok,test1
39> c(test2).                    
test2.erl:2: Warning: export_all flag enabled - all functions will be exported
ok,test2
40> test1:start().               
test2: Im starting with Pid=<0.200.0>
ok,<0.199.0>
41> <0.200.0> ! stop.            
Pid: I exit
Info message goodbye. State = "lol"
stop
** exception exit: badarith
42> gen_server:call(test1, stop).
** exception exit: noproc,gen_server,call,[test1,stop]
     in function  gen_server:call/2 (gen_server.erl, line 215)
43> 

【问题讨论】:

【参考方案1】:

链接是双向的,但陷阱出口不是;您需要在 P1 中调用 process_flag(trap_exit, true)(您当前的代码在 P2 中执行此操作),然后在 handle_info 中处理 'EXIT', FromPid, Reason 形式的消息(将 P2 的 pid 放入 State 以提供帮助)。

在这种情况下,如果 P1 停止,则 P2 停止是有意义的,否则我建议使用 monitor 而不是链接。

旁注:

    使用spawn_link 而不是spawn + link

    spawn 移动到test2:start 会更好。

【讨论】:

Alexey,非常感谢您快速详细的回答!它有效!

以上是关于Erlang gen_server:如何捕获错误?的主要内容,如果未能解决你的问题,请参考以下文章

Erlang中除以零的精确异常类型

如何解决“Erlang 异常错误”

构建 riak:“rebar_core 中未捕获的错误”

尝试构建钢筋时出现“未捕获的 rebar_core 错误”

从源代码编译 MongooseIM 时 rebar_core 中未捕获的错误

从tar安装erlang导致错误,想知道如何指定文件夹