I have an Elixir application that is structured the following way:
Application --> Supervisor --> Worker
The Application Module is fairly simple, it has a use Application
and a
def start(_type, _args)
MyApp.Supervisor.start_link()
end
The Supervisor is a bit more complicated:
def start_link() do
{:ok, pid} = Supervisor.start_link(__MODULE__, [], name: __MODULE__)
halt_exit(wait_for_child())
{:ok, pid}
end
def init(data) do
children =
[
worker(MyApp.Worker, [], restart: :transient)
]
Supervisor.init(children, [strategy: :one_for_one])
end
where halt_exit(pid)
performs a Process.sleep(100)
and then calls itself every time it finds the process pid is still alive (or simply returns nil when pid is not alive anymore), and wait_for_child
finds the Worker module's pid (taking into consideration that it might have to wait until it's started).
My Worker module interacts with the user using IO.puts
and IO.gets
. Why all this complicated unnecessary logic? It seems that
- when using mix run and omit halting exit, the application immediately dies
- when using mix release (distillery) and run
myapp.bat console
from cmd and omit halting exit, my application starts, immediately dies, and then iex is started - when using mix release w/
myapp.bat console
and include halting exit, my app outputs correctly, but can't receive any input (and by this I mean I can't type into the window of werl.exe) - when using mix release w/
myapp.bat foreground
, my app starts and only then there is an error in the batch file (The system cannot find the file `%get_pid_cmd%`. ERROR: The search filter cannot be recognised. '@call' is not recognized as an internal or external command, operable program or batch file.) at which point my app terminates. - when using mix run --no-halt (no exit-halting logic inside app), my app starts, terminates immediately, and the erlang VM remains running in the cmd window
- only when I mix run and include
halt_exit/1
does my app works as expected
From all this, I concluded that 1) the moment my application module's start/2
returns, the app is shut down, which doesn't make much sense as Elixir is designed for applications that put the load on other processes instead of, not besides the application's main module. 2) input is done through the main Application module's process (but for some reason only when run in a separate werl.exe window, seems to work fine with mix run), so I can't put any blocking-until-work-finished logic there if I want my user input.
How can I solve this, and equally importantly (so I can avoid future problems) what behaviour causes my problem? I would need to be able to run this on a computer without mix and Erlang VM installed, so my only option is to make it work with the distillery package generated, which at the moment I can't.
No amount of googling has led me to similar tactics to artificially halt exit, and no forum/tutorial I've found mentions problems with this "early-exit" so I guess the correct way to solve this would be to somehow get it not want to exit while any process is running.
group_leader
system in erlang. (stackoverflow.com/a/36410816/1650580) – Mike Buhot