I have investigated a bit the solution with the signal handler.
Erlang executes :init.stop()
on SIGTERM
by default. That means that a simple kill PID
shuts the thing down orderly.
However, you need to figure out the PID of the process, and open a different terminal to execute the command. Besides, custom code passed to System.at_exit/1
is not invoked by the event handler.
Ctrl-C
sends SIGINT
. The only shortcut that I’ve seen sends a different signal is Ctrl-\
, which sends SIGQUIT
. So, I am using this event handler:
defmodule QuitScript do
@behaviour :gen_event
def init(_), do: {:ok, nil}
def handle_event(:sigquit, _state), do: :remove_handler
def handle_event(signal, state), do: :erl_signal_handler.handle_event(signal, state)
def handle_call(_, state), do: {:ok, :ok, state}
def terminate(_reason, _state) do
IO.puts("My exit code")
System.stop()
end
end
:gen_event.swap_handler(:erl_signal_server, {:erl_signal_handler, []}, {QuitScript, []})
Notice that the terminate/2
callback allows you to run custom code on exit.
If you throw that to a script and execute it for example like this
mix run --no-halt foo.exs
Ctrl-C
still behaves as always, and additionally Ctrl-\
shuts the thing down orderly (you only see ^\
echoed in the terminal, not too bad).