Search code examples
erlangelixirgen-server

DynamicSupervisor.start_child(...) ----> error > already started


I have this code:

defmodule MyApp.JobRunner do
  use DynamicSupervisor
  alias MyApp.MyWorker

  def start_link(_arg) do
    DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    IO.puts("MyApp.JobRunner: init")
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def add_new_task(my_task_id) do
    child_spec = {MyWorker, {my_task_id}}
    IO.puts("MyApp.JobRunner: child_spec > #{Kernel.inspect(child_spec)}")

    res = DynamicSupervisor.start_child(__MODULE__, child_spec)
    IO.puts("MyApp.JobRunner: add_new_task > #{Kernel.inspect(res)}")
    res
  end

Each time I'll call add_new_task(my_task_id) with a new argument, it'll return an error

{:error, {{:badmatch, {:error, {:already_started, #PID<0.550.0>}}},

What's the matter? How is it "already started" if it's called a new argument each time?


MyApp.MyWorker is a GenServer. Can this error have to do with the way it's implemented in my project? I can provide the code


Solution

  • In MyWorker.start_link do you have something like GenServer.start_link(__MODULE__, init_arg, name: __MODULE__)? If so you'll only be able to start one child because the __MODULE__ macro gets replaced by MyWorker and there can only be one process with that name.

    You need a new name for each child. Since you initial state you are passing in is {my_task_id} use that as the name:

      defmodule MyWorker do
        def start_link({name}) do
          GenServer.start_link(__MODULE__, initial, name: name)
        end
      end