Errors and processes in erlang

Previous posts about http://learnyousomeerlang.com: Dog FSM, Cat FSM.

Chapter Errors And Processes is closer to the beginning of the book and deals with core Erlang concepts: error propagation and error trapping.

First off, here is what I wrote to better understand the section that starts with words “the results of uncaught throws, errors and exits in neighboring processes”:

-module(simple_exit_demo).
-export([simple_exit_demo/0]).
simple_exit_demo() ->
spawn(fun() -> start_processes() end).
start_processes() ->
process_flag(trap_exit, true),
spawn_link(fun() -> timer:sleep(1000) end),
spawn_link(fun() -> timer:sleep(2000), exit(exiting_for_a_reason) end),
spawn_link(fun() -> timer:sleep(3000), exit(normal) end),
spawn_link(fun() -> timer:sleep(4000), 1 / 0 end),
spawn_link(fun() -> timer:sleep(5000), erlang:error(raising_error) end),
spawn_link(fun() -> timer:sleep(6000), throw(throwing_error) end),
listen_to_exits().
listen_to_exits() ->
receive
Message -> io:format("Caught a system message: ~p~n~n", [Message]),
listen_to_exits()
after 7000 ->
io:format("Show's over~n")
end.

Here how the demo works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1> c(simple_exit_demo).
./simple_exit_demo.erl:12: Warning: this expression will fail with a 'badarith' exception
{ok,simple_exit_demo}
2> simple_exit_demo:simple_exit_demo().
<0.38.0>
Caught a system message: {'EXIT',<0.39.0>,normal}

Caught a system message: {'EXIT',<0.40.0>,exiting_for_a_reason}

Caught a system message: {'EXIT',<0.41.0>,normal}

Caught a system message: {'EXIT',<0.42.0>,
                             {badarith,
                                 [{simple_exit_demo,
                                      '-start_processes/0-fun-3-',0}]}}

3>
=ERROR REPORT==== 30-Dec-2011::22:42:58 ===
Error in process <0.42.0> with exit value: {badarith,[{simple_exit_demo,'-start_processes/0-fun-3-',0}]}

Caught a system message: {'EXIT',<0.43.0>,
                             {raising_error,
                                 [{simple_exit_demo,
                                      '-start_processes/0-fun-4-',0}]}}

3>
=ERROR REPORT==== 30-Dec-2011::22:42:59 ===
Error in process <0.43.0> with exit value: {raising_error,[{simple_exit_demo,'-start_processes/0-fun-4-',0}]}


=ERROR REPORT==== 30-Dec-2011::22:43:00 ===
Error in process <0.44.0> with exit value: {{nocatch,throwing_error},[{simple_exit_demo,'-start_processes/0-fun-5-',0}]}

Caught a system message: {'EXIT',<0.44.0>,
                             {{nocatch,throwing_error},
                              [{simple_exit_demo,'-start_processes/0-fun-5-',
                                   0}]}}

Show's over
3>

The second chunk of code I’ve written helps understand how the kill reason is different from other kill reasons:

-module(kill).
-export([kill_demo/0]).
listen() ->
receive
Message -> io:format("~p has caught a system message: ~p~n~n", [self(), Message]),
listen()
after 1000 ->
io:format("I, ~p, live on~n", [self()]),
listen()
end.
kill_demo() ->
Pid = spawn_link(fun()->
process_flag(trap_exit, true),
listen()
end),
% this will fail, the recipient process traps all exit signals
timer:sleep(3000),
io:format("Sending exit(Pid, please_die) ~p to ~n", [Pid]),
exit(Pid, please_die),
% "The kill reason acts as a special signal that can't be trapped."
% this will succeed
timer:sleep(4000),
io:format("Sending exit(Pid, kill) ~p to ~n", [Pid]),
exit(Pid, kill).
view raw kill.erl hosted with ❤ by GitHub

The system process traps an exit and lives on, while exit(Pid, kill) kills it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1> c(kill).
{ok,kill}
2> kill:kill_demo().
I, <0.38.0>, live on
I, <0.38.0>, live on
I, <0.38.0>, live on
Sending exit(Pid, please_die) <0.38.0> to
<0.38.0> has caught a system message: {'EXIT',<0.31.0>,please_die}

I, <0.38.0>, live on
I, <0.38.0>, live on
I, <0.38.0>, live on
Sending exit(Pid, kill) <0.38.0> to
** exception exit: killed
3>