I've been learning elixir for only a few weeks, and I want to set up a proper application with it's Application module, Supervisor, and (only one, for the moment) worker.
Days of going through tutorials, documentation, the Elixir forum, and stackoverflow has led me to this understanding:
- I need to have a module which has
use Application
- I don't need to have a separate module for the Supervisor, calling
Supervisor.start_link/2
and storing the returned pid is enough for a simple application. - the Application module has a
start/2
function which returns{:ok, pid}
(which is the return value of the last call in it,Supervisor.start_link(worker_module, options)
) - I need to have a Worker module, which defines
child_spec/2
,init/1
andstart_link/1
Supervisor.start_link/2
callsinit/1
and thenstart_link/1
on the worker with the given optionsinit/1
returns a certain value
Now, I have a problem with the last part. According to the error I get, my worker's init
function returns a "bad value", but I can't figure out what should be the return value for supervisor.start_link/2
not to fail.
The values I have already tried, when init is defined as init(opts)
:
- nil
- {:ok, self()}
- {:ok, __MODULE__}
- {:ok, opts}
- Task.start_link(fn() -> function_that_actually_does_the_work() end)
- :normal
This is the error message I get from the logger after the line {:ok, pid} = Supervisor.start_link(MyAppMain.Worker, [])
:
** (Mix) Could not start application myapp: exited in: MyAppMain.start(:normal, [])
** (EXIT) an exception was raised:
** (MatchError) no match of right hand side value: {:error, {:bad_return, {MyAppMain.Worker, :init, {:ok, %{}}}}}
lib/MyAppMain.ex:15: MyAppMain.start/2
(kernel) application_master.erl:273: :application_master.start_it_old/4
So, what return values does Supervisor.start_link/2
accept?
EDIT: some actual code
Application module:
defmodule MyAppMain do
use Application
def start(_type, _args) do
{:ok, pid} = Supervisor.start_link(MyAppMain.Worker, [])
end
end
Worker module:
defmodule MyAppMain.Worker do
def child_spec(opts) do
%{
id: MyAppMain.Worker,
start: {__MODULE__, :start_link, []},
restart: :transient,
type: :worker
}
end
def start_link(state) do
do_work() # returns a "fn() -> nil end", because "expected a function"
end
def init(opts) do
{:ok, %{}} # Also tried putting the elements of the above list here.
end
defp do_work()
#do some work
if(prompt_restart()) do
do_work()
else
fn() -> nil end
end
end
defp prompt_restart() do
# prompt the user whether to repeat the task via IO.gets, return either true or false
end
end