[erlang-questions] supervisor:start_child

81 views
Skip to first unread message

Martin Dimitrov

unread,
May 2, 2011, 8:32:26 AM5/2/11
to erlang-q...@erlang.org
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.

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?

Thanks,

Regards,

Martin

Mihai Balea

unread,
May 2, 2011, 12:13:16 PM5/2/11
to Martin Dimitrov, erlang-q...@erlang.org

On May 2, 2011, at 8:32 AM, Martin Dimitrov wrote:

> 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

Martin Dimitrov

unread,
May 2, 2011, 12:38:40 PM5/2/11
to erlang-q...@erlang.org
Thanks for the advise about the interface.

> 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.

Isn't the process id the natural choice for these purposes?

So there is no way to avoid the need of unique ids if using anything other than simple_one_for_one?

Regards,

Martin



-------- Оригинално писмо --------
От: Mihai Balea mi...@hates.ms
Относно: Re: [erlang-questions] supervisor:start_child
До: Martin Dimitrov
Изпратено на: Понеделник, 2011, Май 2 19:13:16 EEST

Gregory Haskins

unread,
May 2, 2011, 1:17:23 PM5/2/11
to erlang-q...@erlang.org
On 5/2/11 12:38 PM, Martin Dimitrov wrote:
> Thanks for the advise about the interface.
>
>> 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.
>
> Isn't the process id the natural choice for these purposes?

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

signature.asc

Mike Oxford

unread,
May 2, 2011, 2:25:57 PM5/2/11
to Gregory Haskins, erlang-q...@erlang.org
You can also "not register" them, either locally or globally.  In your child's start_link, use the gen_server/3 instead of gen_server/4.

You cannot do a "whereis(service)" type call, but your children will run and you won't get the conflicting IDs.

-mox

Martin Dimitrov

unread,
May 2, 2011, 2:30:39 PM5/2/11
to Mike Oxford, erlang-q...@erlang.org
> You can also "not register" them, either locally or globally.  In your child's start_link, use the gen_server/3 instead of gen_server/4.

I do this but when using the same id for the specification, I receive already_started error. I believe both need to be unique but my question is why.

Regards,

Martin



-------- Оригинално писмо --------
От: Mike Oxford mox...@gmail.com
Относно: Re: [erlang-questions] supervisor:start_child
До: Gregory Haskins
Изпратено на: Понеделник, 2011, Май 2 21:25:57 EEST

Gregory Haskins

unread,
May 2, 2011, 3:43:31 PM5/2/11
to Martin Dimitrov, erlang-q...@erlang.org
On 5/2/11 2:30 PM, Martin Dimitrov wrote:
>> You can also "not register" them, either locally or globally. In your
> child's start_link, use the gen_server/3 instead of gen_server/4.
>
> I do this but when using the same id for the specification, I receive
> already_started error. I believe both need to be unique but my question
> is why.

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

signature.asc

Martin Dimitrov

unread,
May 2, 2011, 4:19:59 PM5/2/11
to Gregory Haskins, erlang-q...@erlang.org
Thanks for the explanation. In our app we actually use the sup functions (delete_child and so on) but we keep only the pids and since the relationship is one-to-one we retrieve the dynamic id. I thought that there might be an easier way but from what I understand now there isn't.

Thank you all for the help.

Regards,

Martin

Vance Shipley

unread,
May 2, 2011, 4:56:38 PM5/2/11
to Martin Dimitrov, erlang-q...@erlang.org
On Mon, May 02, 2011 at 11:19:59PM +0300, Martin Dimitrov wrote:
} In our app we actually use the sup functions (delete_child and so on)
} but we keep only the pids and since the relationship is one-to-one

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

Reply all
Reply to author
Forward
0 new messages