Reputation: 4329
Ignoring the absence of the Mix config file, I write the following:
defmodule Test.Supervisor do
use Supervisor
def start_link do
#"name:" will show up in :observer...
Supervisor.start_link(__MODULE__, [], [name: :"root_supervisor"])
end
def init(args) do
children = [
worker(Test.Method, [], [function: :start, id: "my_root_process"]),
]
supervise(children, [strategy: :one_for_one, name: :root])
end
end
defmodule Test do
def start(_type, _args) do
Test.Supervisor.start_link()
end
end
defmodule Test.Method do
def start do
IO.puts("Expect to see me often... #{self}")
end
end
Which crashes after the first run (iex -S mix) without restarting the application. The error message is:
=INFO REPORT==== 14-Jan-2016::22:34:04 ===
application: logger
exited: stopped
type: temporary
** (Mix) Could not start application mememe: Test.start(:normal, {}) returned
an error: shutdown: failed to start child: "my_root_process"
** (EXIT) :ok
If however, I change Test.start()
to call Test.Method.start()
directly, like so:
defmodule Test do
def start(_type, _args) do
Test.Method.start()
end
end
Then it runs fine, but then the code won't be supervised. I'm quite sure I'm making an elementary mistake either in implementation, or comprehension here, but what is that mistake exactly?
Upvotes: 3
Views: 1155
Reputation: 9299
There are couple of problems with your code. Firstly, you need a long running function to supervise. Something like:
def loop do
receive do
_anything -> IO.puts "Expect to see me often"
end
loop
end
Then in Test.Method
module, you have to spawn it.
def start do
IO.puts("Starting...")
pid = spawn_link(&loop/0)
{:ok, pid}
end
It is important, that start function returns tuple {:ok, pid_to_supervise}
. It was crashing your app, because supervisor expected a process to monitor, but got only atom :ok
returned by IO.puts
. Worker specification does not spawn new process. It requires a function, that will return pid of spawned process.
You should also link supervisor to the supervised process, so in the end it might be good idea to rename the function to start_link
, instead of start
as @Jason Harrelson suggested.
This should be enough to properly start your project. Note, that you will not see your processes in observers Applications
section. You are not using Application
behaviour, so your root_supervisor
will be floating somewhere. You can find it in Processes
tab. my_root_process
is an id to use withing supervisor, so it won't be visible even in Processes
tab.
Spawning process this way is easy for educational purposes, but in real world system, you would like your processes to follow OTP design principles. It means reacting to system messages, better logging, tracing and debugging. Making process that meets all requirements is quite hard, but you don't have to do it manually. All behaviours implement those principles for you.
So instead of spawning a process with loop, try using GenServer
.
Upvotes: 2
Reputation: 2693
I would try changing the Test.Method.start
function to a Test.Method.start_link
function and stop using the function: :start
in your opts to the worker function. The supervisor calls start_link
by default and there is no reason to break these semantics as the supervisor will always link to the supervised process. If this does not work then at least we have ruled an issue in this area out.
Upvotes: 2