Signals in Erlang

Here’s the translation of the Go signals example to Erlang, formatted for Hugo:

-module(signals).
-export([main/0]).

main() ->
    % Erlang signal handling works by sending messages to the process
    % We'll create a process to receive these notifications
    SignalHandler = spawn(fun() -> signal_handler() end),

    % Register the process to receive notifications of the specified signals
    ok = os:set_signal(sigint, SignalHandler),
    ok = os:set_signal(sigterm, SignalHandler),

    % We could receive signals here in the main function, but let's see
    % how this could also be done in a separate process, to demonstrate
    % a more realistic scenario of graceful shutdown.
    Done = make_ref(),

    % This process executes a blocking receive for signals. When it gets
    % one it'll print it out and then notify the program that it can finish.
    spawn(fun() ->
        receive
            {os_signal, Signal} ->
                io:format("~n~p~n", [Signal]),
                SignalHandler ! {self(), Done}
        end
    end),

    % The program will wait here until it gets the expected signal
    % (as indicated by the process above sending a message) and then exit.
    io:format("awaiting signal~n"),
    receive
        {_, Done} ->
            io:format("exiting~n")
    end.

signal_handler() ->
    receive
        {From, Ref} ->
            From ! {self(), Ref};
        _ ->
            signal_handler()
    end.

Erlang signal handling works differently from Go, but we can achieve similar functionality. Here’s how the Erlang version works:

  1. We define a main/0 function as the entry point of our program.

  2. Instead of channels, Erlang uses message passing between processes. We spawn a signal_handler process to handle signals.

  3. We use os:set_signal/2 to register our signal handler process for SIGINT and SIGTERM signals.

  4. We spawn another process that waits for a signal message and then notifies the main process.

  5. The main process waits for the notification before exiting.

When we run this program, it will block waiting for a signal. By pressing Ctrl+C (which the terminal shows as ^C), we can send a SIGINT signal, causing the program to print the signal and then exit.

$ erl -noshell -s signals main -s init stop
awaiting signal
^C
sigint
exiting

This example demonstrates how to handle signals in Erlang, providing a way for Erlang programs to gracefully respond to system signals like SIGINT or SIGTERM.