Erlang gen_server: как отлавливать ошибки? - PullRequest
0 голосов
/ 23 февраля 2019

Я новичок в разработке Erlang и меня интересуют взаимосвязи процессов.

Если мы свяжем два процесса P1 и P2 с process_flag(trap_exit, true) и будем использовать конструкцию, такую ​​как Pid ! msg и receive .. after .. end - этовозможно отловить ошибки P1, например badarith, вторым процессом P2.

Но если мы используем gen_server процесс P1, связанный с P2, - P1 завершается после сбоя P2.

Итак, как отловить exit() ошибки с помощью gen_server?

Заранее спасибо!

PS Код тестирования.

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.

Результат: процесс test1 завершается неудачно после выхода из test2 с badarith.

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 Ответ

0 голосов
/ 23 февраля 2019

Связывание является двунаправленным, но выходы захвата - нет;вам нужно позвонить process_flag(trap_exit, true) в P1 (ваш текущий код делает это в P2), а затем обработать сообщения вида {'EXIT', FromPid, Reason} в handle_info (поместите pid P2 в State, чтобы помочь).

В этом случае P2 имеет смысл остановиться, если P1 делает, иначе я бы предложил использовать монитор вместо ссылки.

Примечания:

  1. Используйте spawn_link вместо spawn + link.

  2. Это лучший стиль для перемещения spawn в test2:start.

...