EoF - Chapter 3 - Robustness
I know it’s been a few days, but it’s finally time to continue our journey through the Erlang Getting Started guide. Now we’re covering the chapter on Robustness.
Robustness, if I had to describe it simply, is a measure of how well a piece of
software handles faults, errors, and other kinds of unanticipated or unintended
behaviour. Robust software generally use things like exception-handling (your
typical try/catch
style blocks), graceful shutdown, and even graceful
degradation.
In Erlang, the focus is on multi-process communication, so writing robust Erlang focuses on problems that may arise there. What happens when a child process exits unexpectedly? What happens when a child is unresponsive?
Timeouts
We’ll actually start with the second of these considerations: an unresponsive
child. The receive
construct mentioned in the
last chapter causes a process to pause
until it receives a message that matches one of it’s handling patterns. an
optional after
clause can be included after receive
, which is given a
number of milliseconds to wait before it is automatically triggered:
receive
{other, pattern} ->
do_some_stuff()
after 5000 ->
io:format("Sound the alarm~n", [])
end.
In the above cause, execution pauses on the receive
until a message matching
the pattern {other, pattern}
is received (a 2-ple of atoms). If 5000ms passes
without said message arriving, then "Sound the alarm"
is printed to the
console.
Errors
If an Erlang process explicitly experiences an error (rather than becoming nonresponsive like the above), it can send an exit message to any “linked” processes.
A two-way link for this purpose can be established between two processes by
using the built-in function link
:
start() ->
Other_PID = spawn(other_module, module_fn, []),
link(Other_PID).
This can be compressed into one function call with the spawn_link
function:
start() ->
spawn_link(other_module, module_fn, []).
Afterward, if the current process, or the process that was spawned exits, it
will send a message of the form {'EXIT', FromPID, Reason}
to all of it’s
linked processes.
Processes can be explicitly instructed to exit normally using exit(normal)
or
abnormally using exit(Reason)
, where Reason
is any Erlang data (except for
normal
, obviously).
The chapter concludes by bringing back the messenger application example from
the previous chapter and improving its robustness with linking, exit signals,
and a timeout. It also mentions that attempting to link
to a non-existent
process causes the exit signal {'EXIT', From, noproc}
to be automatically
generated, allowing the current process to act as if the process it attempted
to link
to has just exited.
That’s it for this one – a pretty concise chapter, but immensely useful. The next chapter is “Records and Macros”. It covers larger project structures and where to put configuration details (hint: macros) and message interface details (hint: records). Later!
— M