Signals in Elixir

Here’s the translation of the Go code to Elixir, with explanations in Markdown format suitable for Hugo:

Elixir provides mechanisms to handle Unix signals, allowing programs to gracefully respond to events like termination requests or interrupts. Here’s how to handle signals in Elixir using the :os.signal/2 function and message passing.

defmodule SignalHandler do
  def start do
    # Register the process to receive SIGINT and SIGTERM signals
    :os.set_signal(:sigint, :handle)
    :os.set_signal(:sigterm, :handle)

    # Print a message indicating we're waiting for a signal
    IO.puts("awaiting signal")

    # Start the signal handling loop
    handle_signals()
  end

  defp handle_signals do
    receive do
      {:os_signal, signal} ->
        IO.puts("\n#{signal}")
        IO.puts("exiting")
    end
  end
end

# Start the signal handler
SignalHandler.start()

In Elixir, we use the :os.set_signal/2 function to register our process to receive specific signals. We’re interested in SIGINT (interrupt) and SIGTERM (termination) signals.

The handle_signals/0 function uses Elixir’s receive block to wait for signal messages. When a signal is received, it’s printed, and then the program exits.

Unlike Go, Elixir doesn’t use channels for signal handling. Instead, it uses Erlang’s built-in message passing system. The operating system sends signals as messages to the registered process.

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

$ elixir signals.exs
awaiting signal
^C
SIGINT
exiting

In this Elixir version, we’ve maintained the core functionality of the original Go program while adapting it to Elixir’s idioms and concurrency model. The program still waits for a signal and gracefully exits when one is received.