Chapter 6: A Supervisor Example

82 views
Skip to first unread message

Jaime Enriquez

unread,
Feb 28, 2013, 5:33:24 PM2/28/13
to erlang-prog...@googlegroups.com
Hello Erlang users

I was testing the Supervisor Example and I could not make it to work perfectly as it is shown ending the chapter. Namely, the following lines are in order to depict that the examples works well.

1> my_supervisor:start_link(my_supervisor, [{add_two, start, []}]).
ok
2> whereis(add_two).
<0,125,0>
3> exit(whereis(add_two), kill).
true
4> add_two
:request(100).
102
5> whereis(add_two).

When I debugged the example, at step 3: exit(whereis(add_two), kill)., the debugger showed me that "my_supervisor" did not actually received any exit message, therefore, the restart_child/2 function did not take place until step 4, however. the shell at step 4 returned: "** exception error: bad argument in function add_two:request/1..." followed by a 'EXIT' match in the receive clause in "my_supervisor. loop/1 function" but the requester Pid (the shell in this case) would never match in the list ChildList in the restart_child/2 function.

I checked every single line of the my_supervisor code file and add_two code file so as to find any bad-typping or logic error made by me but everything was according to the book.

Thinking a bit more about the logic of the supervisor example, the theory says that 2 processes need to be linked if we want them to send any EXIT signal originated in any process to the other and they need to be trapping exits if we want to convert those EXIT signals as messages. Having said that, I linked my_supervisor with the add_two process and everything worked like a charm.

My question is: was that correct? were not the my_supervisor and add_two processes supposed to be linked each other?, perhaps, that link/1 line(s) was/were accidentally left out from the supervisor example?.

Here is the complete code, which is almost the same, with the link/1 lines highlighted.

-module(my_supervisor).
-export([start_link/2, stop/1]).
-export([init/1]).

start_link(Name, ChildSpecList) ->
    register(Name, spawn_link(my_supervisor, init, [ChildSpecList])),
    ok.

init(ChildSpecList) ->
    process_flag(trap_exit, true),
    loop(start_children(ChildSpecList)).

start_children([]) ->
    [];
start_children([{M, F, A} | ChildSpecList]) ->
    case (catch apply(M, F, A)) of
    {ok, Pid} ->
        %% I linked the new created worker with me "the supervisor"
        link(Pid),
        [{Pid, {M, F, A}} | start_children(ChildSpecList)];
    _ ->
        start_children(ChildSpecList)
    end.

restart_child(Pid, ChildList) ->
    {value, {Pid, {M, F, A}}} = lists:keysearch(Pid, 1, ChildList),
    {ok, NewPid} = apply(M, F, A),

    link(NewPid),
    [{NewPid, {M, F, A}} | lists:keydelete(Pid, 1, ChildList)].

loop(ChildList) ->
    receive
    {'EXIT', Pid, _Reason} ->
        NewChildList = restart_child(Pid, ChildList),
        loop(NewChildList);
    {stop, From} ->
        From ! {reply, terminate(ChildList)}
    end.

stop(Name) ->
    Name ! {stop, self()},
    receive
    {reply, Reply} ->
        Reply
    end.

terminate([{Pid, _} | ChildList]) ->
    exit(Pid, kill),
    terminate(ChildList);
terminate(_ChildList) -> ok.
Reply all
Reply to author
Forward
0 new messages