fxn

fxn

Running code when a script exits

I have a script executed with mix run that has an infinite loop that collects some data in an agent. I’d like to print that data when I interrupt the script.

Tried System.at_exit/1 without success, maybe because the only way I know to interrupt the execution is C-c C-c.

Is there a way to accomplish that?

Most Liked

josevalim

josevalim

Creator of Elixir

There are two questions here:

  1. How to shut the system down cleanly

  2. How to handle certain signals (interrupt)

To answer 1, System.stop/1 is the answer. If terminate/2 callbacks are not invoked, make sure those processes are trapping exits.

To answer 2, since Erlang/OTP 20, there is OS signal handling: http://erlang.org/doc/man/kernel_app.html#os-signal-event-handler

It is a bit of a long answer. In a nutshell, you need to implement a gen_event handler and react to the callbacks you are interested. There is a more detailed guide here: https://medium.com/@ellispritchard/graceful-shutdown-on-kubernetes-with-signals-erlang-otp-20-a22325e8ae98

josevalim

josevalim

Creator of Elixir

Another trick you could do is System.at_exit(fn int -> your_code(); System.stop(int) end). :slight_smile:

fxn

fxn

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).

Last Post!

fxn

fxn

Alternatively, we could move System.stop() to the callback:

defmodule QuitScript do
  @behaviour :gen_event

  def init(_), do: {:ok, nil}
  def handle_event(:sigquit, _state), do: System.stop()
  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")
  end
end

:gen_event.swap_handler(:erl_signal_server, {:erl_signal_handler, []}, {QuitScript, []})

Looks more natural to me this way, though in the previous example the order in which the custom code runs is more obvious.

Where Next?

Popular in Questions Top

hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

We're in Beta

About us Mission Statement