Child spec and default arguments in start_link

With introduction of child_spec the default start option changed to start_link/1 from start_link/2. Resulting this change means that setting default arguments in start_link/0 (handy in testing for dependency injection) does not work anymore.

Given the following supervisor child option:

children = [worker(Worker, [])]

and given following worker

def start_link(opts \\ [name: @name, queue: @queue]) do
    IO.inspect opts, label: "PRODUCER"
    GenStage.start_link(__MODULE__, opts[:queue], opts)
end

My worker will have defaults for queue and opts when started through the supervisor and in my tests I can overwrite the name to be something else.

Now with the new way of setting up a supervisor using child_spec definitions this does not work, given the following supervisor

Supervisor.init([Worker])

and given the same Worker, slightly changed so start points to start_link/0

use GenStage, start: {__MODULE__, :start_link, []}
def start_link(opts \\ [name: @name, queue: @queue]) do
    IO.inspect opts, label: "PRODUCER"
    GenStage.start_link(__MODULE__, opts[:queue], opts)
end

My worker is correctly started using the supervisor but when manually starting in my specs my overwrite do not get registered. I use the following code to start the Worker manually

setup context do
    {:ok, worker} = start_supervised({Worker, [name: context.test]})
    %{worker: worker}
  end

Whatever I do the name of the process will always be the default @name, I cannot seem to change it at all. What does work is the following (but a bit ugly IMO)

def start_link(opts) when opts == [], do: start_link([name: @name, queue: @queue])
def start_link(opts) do
    IO.inspect opts, label: "PRODUCER"
    GenStage.start_link(__MODULE__, opts[:queue], opts)
  end

Is there a better way to do this?

def start_link(opts) do
    opts = Keyword.merge([name: @name, queue: @queue], opts);
    IO.inspect opts, label: "PRODUCER"
    GenStage.start_link(__MODULE__, opts[:queue], opts)
end

Thanks thats indeed another solution, I’m just wondering why my initial solution would not work

use GenStage, start: {__MODULE__, :start_link, []}

This tells the supervisor to call start_link/0. So when you call start_supervised in your tests, it doesn’t matter what arguments you pass: start_link/0 does not take any.