Hello,
I am confused by the various start_link/X signatures and the number of arguments they accept depending on the context (and especially the fact that default child_specs use start_link/1
, preventing from sending options in addition to args).
What I want to do is to start several instances of a given GenServer by specifying a :name
, something that would look like (without a Supervisor):
GenServer.start_link(Stack, args1, name: :stack1)
GenServer.start_link(Stack, args2, name: :stack2)
In this case it’s possible to spawn GenServers with specific args and names.
Now with a Supervisor, the steps are (see doc):
1 - create a spec with an empty args list so that it can be overriden by each child (I don’t understand why it is necessary since we are going to specify a :simple_one_for_one
strategy right after). The doc gives this example:
spec = Supervisor.child_spec(Agent, start: {Agent, :start_link, []})
But in a module we can also override the spec:
defmodule Stack do
use Agent, start: {Stack, :start_link, []}
...
end
spec = Stack.child_spec(:useless_ugly_parameter)
Or even define a child_spec/0
without this :useless_ugly_parameter.
2 - Start the supervisor with the spec:
{:ok, sup_pid} = Supervisor.start_link([spec], strategy: :simple_one_for_one)
3 - Start children:
{:ok, child1} = Supervisor.start_child(sup_pid, [args1])
{:ok, child2} = Supervisor.start_child(sup_pid, [args2])
Now it seems it’s not possible to send options (like :name) to child with start_child
.
Possible solutions:
- put the options in the args, something like:
{:ok, child} = Supervisor.start_child(sup_pid, [{args, options}])
And within Stack.start_link/1
destructure it so that we only send args to init/1
. Something like:
def start_link({args, options}) do
GenServer.start_link(__MODULE, args, options)
end
- or define a child spec that would use
start_link/2
(rather thanstart_link/1
), but I don’t know how to do it.
Even if both may be possible, I think this adds complexity to a typical scenario.