Search code examples
elixirgen-servererlang-supervisor

worker exits after starting in Supervisor


I am trying to start the below workers in a Supervisor that I am calling in application module in mix.exs

Like this

defmodule AppStarter do
import Supervisor.Spec
def start(_type,_args) do
    children=[
        worker(TPMod1,[],[]),
        worker(TPMod2,[],[])
    ]
    opts=[strategy: :one_for_one, name: HelloVisor]
    Supervisor.start_link(children,opts)
end


end

One of my module is GenServer and another I kept a simple listening process.

defmodule TPMod1 do

def start_link() do
 IO.puts "started TPMod1"
 listen()
end



def listen() do
  receive do
    _ -> :ok
  end
  listen()
end

 def child_spec(opts) do
      %{
        id: __MODULE__,
        start: {__MODULE__, :start_link, []},
        type: :worker,
        restart: :permanent,
        shutdown: 500
      }
    end


end

Problem is it get stuck and doesn't start the worker 2 TPMod2 I tried doing in TPMod1's start_link()

def start_link() do
 IO.puts "started TPMod1"
 Task.async(&listen/0)
end

But that give me this

** (Mix) Could not start application tproject: AppStarter.start(:normal, []) returned an error: shutdown: failed to start child: TPMod1 ** (EXIT) %Task{owner: #PID<0.143.0>, pid: #PID<0.144.0>, ref: #Reference<0.2187290957.3420192769.212288>}

I can make it GenServer and make it work but how can we start a simple worker? And why supervisor is not restarting it again? not infinitly but some times? It should have at least tried restarting and fail. Please suggest other improvements too if any.


Solution

  • The supervisor expects the children to return {:ok, pid}, :ignore or {:error, reason}.

    It hangs because when the supervisor runs the start_link function on your worker, it executes (as himself), listen which sets a receive block, so it gets stuck there. When you use the gen_* module's start_link and friends, it takes care of spawning, returning correctly etc.

    In your case you could switch:

    def start_link() do
     IO.puts "started TPMod1"
     listen()
    end
    

    to:

    def start_link() do
     pid = spawn(__MODULE__, :listen, [])
     {:ok, pid}
    end
    

    And this should do it.