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