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
    Logger.info("starting")
    children = [{DynamicSupervisor, strategy: :one_for_one, name: Foo}]
    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
    Logger.info("started")
    {:ok, pid}
  end

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

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

https://github.com/erlang/otp/blob/master/erts/preloaded/src/init.erl#L676-L680

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.

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:
https://gist.github.com/mrallen1/806fe5506132260574af33e99dadd499