I have a process which has two arguments given when started, a scope and a user.
def start_link(scope, user) do
GenServer.start_link(__MODULE__, [scope, user])
end
Now I want to manage a lot of these processes via DynamicSupervisor:
def init(scope) do
DynamicSupervisor.init(strategy: :one_for_one, extra_arguments: [scope])
end
def register(user) do
spec = {MyProcess, [user]}
DynamicSupervisor.start_child(__MODULE__, spec) do
{:ok, pid} -> pid
{:error, {:already_started, pid}} -> pid
end
end
The idea behind this is to utilize DynamicSupervisor
's extra_arguments
option to pass the scope when starting the supervisor in my supervision tree.
However this does not work because only one process is ever started, all the other calls to DynamicSupervisor.start_child/2
return a {:error, {:already_started, pid}}
!
I can get the code working like this:
def register(user) do
# FIXME: Dirty dirty hack!
%{extra_arguments: [scope]} = :sys.get_state(__MODULE__)
name = {:via, Registry, {__MODULE__.Registry, [scope, user]}}
spec = %{
id: name,
start: {MyProcess, :start_link, [user, [name: name]]}
}
case DynamicSupervisor.start_child(__MODULE__, spec) do
{:ok, pid} -> pid
{:error, {:already_started, pid}} -> pid
end
end
However this feels very cumbersome and dirty because of
- manually managing the id and name of my child processes
- using
:sys.get_state/1
to get:extra_arguments
again - lots of boilerplate code:
In my opinion DynamicSupervisor
should respect arguments given in the spec and in :extra_arguments
to determine if a child process was already started or not.
Am I doing something wrong?