Mix run and the application behaviour

Lets say I have this module which I use as an entrypoint for my application:

defmodule A do
  use Application

  require Logger

  def start(_, _) do
    children = [{DynamicSupervisor, strategy: :one_for_one, name: Foo}]
    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
    {:ok, pid}

  def stop(_), do: Logger.info("stopped")

When I do mix run I will get propper output about the application start, but not the application shutdown, while there are no stale beam processes left on my system and as such I conclude the application has exited one way or the other.

When I do iex -S mix and exit with C-c C-c, the result is the same. Startup logs are as expected, but no shutdown notice. Of course there are no zombie processes left.

mix run --no-halt, killed by C-c C-c behaves the same. Startup is fine, shutdown happens without logging.

If though I do iex -S mix and use System.stop/0, the application will also print the shut down logs before System.stop/0 will return :ok and iex exits.

Is there a way to get the stop/1 and prep_stop/1 callbacks called reliably?

(Well, I know that there are situations where I can not do that, eg. a kill -9 $myprocess, but lets say “as reliable as my operating system allows for it”).

1 Like

I don’t have much knowledge about this, and I could be way off. But maybe the order in which the processes are killed changes when you call System.stop/0 from iex? Maybe doing it from iex puts application A in a position where its logger message doesn’t get flushed before it is displayed.

What I’m imagining here is: [A, #PID<>, #PID<>, IEx, Logger | rest] when called from IEx.

But when doing C-c, somehow the ordering gets changed to: [#PID<>, #PID<>, A, Logger | rest] where they are getting killed so close together that the message just gets flushed.

Maybe experimenting with something other than Logger would give better insight.

1 Like

Applications are shut down in reverse order that they are started up.

However ‘stop’ is not a reliable callback in the way that it seems requested as there are many ways to take down something without the stop or terminate callbacks being called, see: