Search code examples
elixirerlang-otperlang-supervisor

Why do I get an error from this one level deep OTP tree when I start the child?


Now when I do the following I get an error status from start_child:

{_, pid} = NTree.start_link
{_, cid} = Supervisor.start_child(pid, [])
# {:error, #<PID.0.91.0>}

Why is this? I'm able to send a message like "hello world" to it and get back a printed message via IO.inspect. This means the process is running as far as I can tell.

defmodule NTree do
  # this will be the top line supervisor
  use Supervisor

  def start_link, do: Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)

  def init(:ok) do
    children = [
      worker(TreeWorker, [], restart: :temporary)
    ]

    supervise(children, strategy: :simple_one_for_one)
#   {:ok,
#   {{:simple_one_for_one, 3, 5},
#    [{TreeWorker, {TreeWorker, :start_link, []}, :temporary, 5000, :worker,
#      [TreeWorker]}]}}
  end

  def start_worker(supervisor) do
    persister = Supervisor.start_child(supervisor, [])
  end

end

defmodule TreeWorker do
  def start_link do
    spawn(fn -> loop end)
  end

  def loop do
    receive do
      :stop -> :ok

      msg ->
        IO.inspect msg
        loop
    end
  end
end

Process.info(cid) yields:

[current_function: {TreeWorker, :loop, 0}, initial_call: {:erlang, :apply, 2},
 status: :waiting, message_queue_len: 0, messages: [], links: [],
 dictionary: [], trap_exit: false, error_handler: :error_handler,
 priority: :normal, group_leader: #PID<0.26.0>, total_heap_size: 233,
 heap_size: 233, stack_size: 1, reductions: 141,
 garbage_collection: [min_bin_vheap_size: 46422, min_heap_size: 233,
  fullsweep_after: 65535, minor_gcs: 0], suspending: []]

Solution

  • A worker's start function must return {:ok, pid} on success. TreeWorker.start_link/0 returns only pid. You can fix this by returning {:ok, pid}:

    defmodule TreeWorker do
      def start_link do
        {:ok, spawn(fn -> loop end)}
      end
      ...
    end
    
    iex(1)> NTree.start_link
    {:ok, #PID<0.89.0>}
    iex(2)> NTree.start_worker(NTree)
    {:ok, #PID<0.91.0>}