Running code when a script exits

Temporary hack

Thanks @rvirding! That makes sense. Since Ctrl-G does not trigger a signal, I guess someone needs to be monitoring standard input to do something about it.

By now, I am moving on with a dirty solution, which is to monitor a file:

defmodule Halter do
  @halter "halt"

  def run(on_halt) do
    if File.exists?(@halter) do
      File.rm(@halter)
      on_halt.()
      System.stop()
    else
      Process.sleep(1000)
      run(on_halt)
    end
  end
end

Halter.run(fn -> IO.puts("done") end)

You leave the script running, and touch halt whenever you want it to stop. Enough for my purposes right now.

That solution prints these noisy traces, so it is definitely not clean:

** (exit) exited in: GenServer.call(Mix.ProjectStack, {:get_stack, #Function<10.12591541/1 in Mix.ProjectStack.peek/0>}, :infinity)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (elixir 1.10.3) lib/gen_server.ex:1013: GenServer.call/3

System.at_exit/1 is not invoked (that is why run/1 above receives a callback), I do not know why.

Is this a missing feature?

Not being able to do this easily surprises to me. It is a fundamental aspect of Erlang/OTP that you start applications and, symmetrically, shut them down orderly.

So, given that mix run starts the application by default, you’d expect that there would be interface to shut it down too, no? @josevalim is there a technical reason this is not in place? Or is it something that could be contributed?