> Hi,
>
> I am developing a server that needs to spawn (under supervision) multiple child processes. Since these processes will be of different gen_server type, I cannot use simple_one_of_one restart strategy. These servers are anonymous, I refer to them by their Pids.
I think you might be able to use a simple one for one supervisor to start different types of gen_servers.
You would need to create an interface module to be used in the child spec, a module that would in turn call your various other gen_servers according to some parameters.
I've never done this, but I don't see why it wouldn't work.
>
> The problem I get is when I try to run 2 or more servers from the same type with the same id inside the child specification. I receive already_started error. By making the ids different, everything works fine.
>
> My question is why the id inside the child specification needs to be different for every process (even if it is of the same type)? What is the best practice to deal with this? Can the creation of dynamic ids be avoided?
A normal (i.e. not simple_on_for_one) supervisor allows you to stop, restart and delete children processes, so it needs a way to identify them. Hence the id.
Mihai
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions
Its chicken and egg, though. The supervisor spawns the process and you
have to give it an ID to instruct it to start_child() in the first place.
>
> So there is no way to avoid the need of unique ids if using anything
> other than simple_one_for_one?
When I don't care, I just use erlang:now() for the ID. Sloppy, perhaps,
but it gets the job done.
Kind Regards,
-Greg
The supervisor ID is a "supref" name-space that uniquely identifies the
_childspec_, so that it may be later referred to with terminate_child(),
delete_child(), and restart_child().
The first parameter in gen_server:start_link/4 is a process namespace
(actually, two: global and local) that uniquely identifies the _pid_.
In both cases, the name given _must_ be unique, though you can opt not
to specify a name in the pid namespace by using gen_server/3. As far as
I know, you must always specify a name in the supref namespace, though
you can use a throw-away value (like erlang:now()) if you don't ever
care to terminate/delete/restart that particular child (at least via the
supervisor module).
So to answer your question, they both must be unique simply because the
namespaces in question do not allow duplicate entries. However, the
namespaces do not really relate to one another, and one of them is
optional (i.e. via use of gen_server/3).
Hope that helps,
-Greg
But really the relationship is not one to one but one to many,
at least over time. Consider this:
Start a supervisor with one child:
1> {ok, Sup} = supervisor:start_link(super, []).
{ok,<0.33.0>}
Start a new child:
2> Id = make_ref().
#Ref<0.0.0.32>
3> ChildSpec = {Id, {gen_server, start_link, [server, [], []]}, permanent, 4000, worker, [server]}.
{#Ref<0.0.0.32>,
{gen_server,start_link,[server,[],[]]},
permanent,4000,worker,
[server]}
4> supervisor:start_child(Sup, ChildSpec).
{ok,<0.38.0>}
Now we have a process with pid() <0.38.0> created by the child specification:
5> Children = supervisor:which_children(Sup).
[{#Ref<0.0.0.32>,<0.38.0>,worker,[server]},
{server,<0.34.0>,worker,[server]}]
Now something tragic happens to that child:
6> {Id, Pid, _, _} = lists:keyfind(Id, 1, Children).
{#Ref<0.0.0.32>,<0.38.0>,worker,[server]}
7> exit(Pid, oops).
true
That child specification is still identified by the unique reference
however the process it is managing has changed to <0.42.0>:
8> supervisor:which_children(Sup).
[{#Ref<0.0.0.32>,<0.42.0>,worker,[server]},
{server,<0.34.0>,worker,[server]}]
} we retrieve the dynamic id. I thought that there might be an easier
} way but from what I understand now there isn't.
You either need to save the Id or dynamically learn it:
9> {Id, Pid, _, _} = lists:keyfind(Pid, 2, Children).
{#Ref<0.0.0.32>,<0.38.0>,worker,[server]}
I would add though that it is likely you really be considering using
another supervision layer. Start a simple_one_for_one supervisor
for each type of worker under the supervisor you are using now.
--
-Vance