Erlang/OTP Forums

Author Message

<  Erlang questions mailing list  ~  Programming question

Guest
Posted: Wed Jan 24, 2007 12:25 pm Reply with quote
Guest
Hi,

A quick question for Erlang gurus out there.

I have two processes A and B. B spends most of its life in a series
of gen_server calls towards A:

loopB(PidA, S) ->
Res = gen_server:call(PidA, {op, stuff}),
S1 = process(Res, S),
loopB(PidA, S1).

The question is how do I set things up so that if A dies B is killed?

Thanks,
Sean
_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
mats
Posted: Wed Jan 24, 2007 1:49 pm Reply with quote
User Joined: 28 Feb 2005 Posts: 168 Location: budapest,hungary
Sean Hinde wrote:
> Hi,
>
> A quick question for Erlang gurus out there.
>
> I have two processes A and B. B spends most of its life in a series
> of gen_server calls towards A:
>
> loopB(PidA, S) ->
> Res = gen_server:call(PidA, {op, stuff}),
> S1 = process(Res, S),
> loopB(PidA, S1).
>
> The question is how do I set things up so that if A dies B is killed?


as a non-guru, i was thinking that happened automatically as soon as you made
the call?

1> is_process_alive(Pid).
false
2> gen_server:call(Pid, {op, stuff}).
** exited: {noproc,{gen_server,call,[<0.14604.0>,{op,stuff}]}} **

or is that too late?

mats
_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
View user's profile Send private message MSN Messenger
Guest
Posted: Wed Jan 24, 2007 2:08 pm Reply with quote
Guest
El Mi
Guest
Posted: Wed Jan 24, 2007 2:14 pm Reply with quote
Guest
On 24 Jan 2007, at 13:42, Mats Cronqvist wrote:

> Sean Hinde wrote:
>> Hi,
>>
>> A quick question for Erlang gurus out there.
>>
>> I have two processes A and B. B spends most of its life in a series
>> of gen_server calls towards A:
>>
>> loopB(PidA, S) ->
>> Res = gen_server:call(PidA, {op, stuff}),
>> S1 = process(Res, S),
>> loopB(PidA, S1).
>>
>> The question is how do I set things up so that if A dies B is killed?
>
>
> as a non-guru, i was thinking that happened automatically as soon
> as you made
> the call?
>
> 1> is_process_alive(Pid).
> false
> 2> gen_server:call(Pid, {op, stuff}).
> ** exited: {noproc,{gen_server,call,[<0.14604.0>,{op,stuff}]}} **

loopB spends most of its time waiting for a reply to the call. The
likelihood is that Process A will die during the processing of the
call, not while it is being "sent". In that case the above will not
happen. Question still stands Smile

Sean

_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
Guest
Posted: Wed Jan 24, 2007 2:31 pm Reply with quote
Guest
On 24 Jan 2007, at 14:00, Javier Par
uwiger
Posted: Wed Jan 24, 2007 2:34 pm Reply with quote
User Joined: 03 Jul 2006 Posts: 604 Location: Sweden
Through the use of supervisors, you can either set up the
processes under a one_for_all supervisor or a rest_for_one,
where B is started after A. Then, if A dies, the supervisor
will kill B.

BR,
Ulf W

> -----Original Message-----
> From: erlang-questions-bounces@erlang.org
> [mailto:erlang-questions-bounces@erlang.org] On Behalf Of Sean Hinde
> Sent: den 24 januari 2007 15:09
> To: Mats Cronqvist (TN/EAB)
> Cc: Erlang Questions
> Subject: Re: [erlang-questions] Programming question
>
>
> On 24 Jan 2007, at 13:42, Mats Cronqvist wrote:
>
> > Sean Hinde wrote:
> >> Hi,
> >>
> >> A quick question for Erlang gurus out there.
> >>
> >> I have two processes A and B. B spends most of its life in
> a series
> >> of gen_server calls towards A:
> >>
> >> loopB(PidA, S) ->
> >> Res = gen_server:call(PidA, {op, stuff}),
> >> S1 = process(Res, S),
> >> loopB(PidA, S1).
> >>
> >> The question is how do I set things up so that if A dies B
> is killed?
> >
> >
> > as a non-guru, i was thinking that happened automatically
> as soon as
> > you made the call?
> >
> > 1> is_process_alive(Pid).
> > false
> > 2> gen_server:call(Pid, {op, stuff}).
> > ** exited: {noproc,{gen_server,call,[<0.14604.0>,{op,stuff}]}} **
>
> loopB spends most of its time waiting for a reply to the
> call. The likelihood is that Process A will die during the
> processing of the call, not while it is being "sent". In that
> case the above will not happen. Question still stands Smile
>
> Sean
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@erlang.org
> http://www.erlang.org/mailman/listinfo/erlang-questions
>

_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
View user's profile Send private message Visit poster's website
Guest
Posted: Wed Jan 24, 2007 2:58 pm Reply with quote
Guest
Sean Hinde wrote:
> Hi,
>
> A quick question for Erlang gurus out there.
>
> I have two processes A and B. B spends most of its life in a series
> of gen_server calls towards A:
>
> loopB(PidA, S) ->
> Res = gen_server:call(PidA, {op, stuff}),
> S1 = process(Res, S),
> loopB(PidA, S1).
>
> The question is how do I set things up so that if A dies B is killed?

Assuming that normal linking of B to A does not work (e.g. if B is
trapping exits, does not accept an exit message in the waiting state,
and you can't change the code of A and B), you could spawn a small
simple watchdog process, and link it to both A and B. It should wait
for the termination of either of them. If A dies, the watchdog kills
B by brute force, i.e., exit(B, kill). If B dies, the watchdog dies
with it, quietly.

Or you could go the whole OTP hog and use a full supervisor model,
as Uffe suggested.

/Richard

_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
Guest
Posted: Wed Jan 24, 2007 3:16 pm Reply with quote
Guest
On 24 Jan 2007, at 14:28, Ladislav Lenart wrote:

> Sean Hinde wrote:
>> Hi,
>>
>> A quick question for Erlang gurus out there.
>>
>> I have two processes A and B. B spends most of its life in a series
>> of gen_server calls towards A:
>>
>> loopB(PidA, S) ->
>> Res = gen_server:call(PidA, {op, stuff}),
>> S1 = process(Res, S),
>> loopB(PidA, S1).
>>
>> The question is how do I set things up so that if A dies B is killed?
>
> I am not a guru, but if "to die" means to terminate abnormally,
> you can link the two processes. BUT since links are bi-directional,
> if B dies, A will be killed as well.

This won't do it. If A dies while processing the call from B, even
when linked, then B does not die.

>
> If this is not what you want, you can either start trapping exit
> signals OR you might take a look at erlang:monitor. It should
> allow you to create one-directional link. Modify B as follows:
> * Create a monitor to process A (during initialization perhaps)
> and store the resulting reference (Ref) as part of B's internal
> state.
> * Modify loopB so it can receive the following message:
> {'DOWN', Ref, process, PidA, Info}

You will notice that B does not have a receive statement of its own.
It is relying on gen_server, so this will not help.

> where Info is either the exit reason, noproc or noconnection.
> You can terminate the process when this message is received.
>
> BTW I have a question too. If B is implemented in terms of
> gen_server, I have to implement handle_info callback function
> in order to react upon receive of a 'DOWN' message from the
> monitor, right?

Yes, that would be the thing to do. OTP behaviours are pretty
strightforward once you get you head around them

Sean



_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
Guest
Posted: Wed Jan 24, 2007 3:20 pm Reply with quote
Guest
Well, we do not use OTP supervisors. We have our own which implements
something not dissimilar to the timed backoff restarts that someone
asked for recently on the list.

It does not however support the *many supervisor strategies.

Sean

On 24 Jan 2007, at 14:22, Ulf Wiger ((TN/EAB)) wrote:

>
> Through the use of supervisors, you can either set up the
> processes under a one_for_all supervisor or a rest_for_one,
> where B is started after A. Then, if A dies, the supervisor
> will kill B.
>
> BR,
> Ulf W
>
>> -----Original Message-----
>> From: erlang-questions-bounces@erlang.org
>> [mailto:erlang-questions-bounces@erlang.org] On Behalf Of Sean Hinde
>> Sent: den 24 januari 2007 15:09
>> To: Mats Cronqvist (TN/EAB)
>> Cc: Erlang Questions
>> Subject: Re: [erlang-questions] Programming question
>>
>>
>> On 24 Jan 2007, at 13:42, Mats Cronqvist wrote:
>>
>>> Sean Hinde wrote:
>>>> Hi,
>>>>
>>>> A quick question for Erlang gurus out there.
>>>>
>>>> I have two processes A and B. B spends most of its life in
>> a series
>>>> of gen_server calls towards A:
>>>>
>>>> loopB(PidA, S) ->
>>>> Res = gen_server:call(PidA, {op, stuff}),
>>>> S1 = process(Res, S),
>>>> loopB(PidA, S1).
>>>>
>>>> The question is how do I set things up so that if A dies B
>> is killed?
>>>
>>>
>>> as a non-guru, i was thinking that happened automatically
>> as soon as
>>> you made the call?
>>>
>>> 1> is_process_alive(Pid).
>>> false
>>> 2> gen_server:call(Pid, {op, stuff}).
>>> ** exited: {noproc,{gen_server,call,[<0.14604.0>,{op,stuff}]}} **
>>
>> loopB spends most of its time waiting for a reply to the
>> call. The likelihood is that Process A will die during the
>> processing of the call, not while it is being "sent". In that
>> case the above will not happen. Question still stands Smile
>>
>> Sean
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@erlang.org
>> http://www.erlang.org/mailman/listinfo/erlang-questions
>>

_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
Guest
Posted: Wed Jan 24, 2007 3:59 pm Reply with quote
Guest
On 24 Jan 2007, at 14:53, Richard Carlsson wrote:

> Sean Hinde wrote:
>> Hi,
>> A quick question for Erlang gurus out there.
>> I have two processes A and B. B spends most of its life in a
>> series of gen_server calls towards A:
>> loopB(PidA, S) ->
>> Res = gen_server:call(PidA, {op, stuff}),
>> S1 = process(Res, S),
>> loopB(PidA, S1).
>> The question is how do I set things up so that if A dies B is killed?
>
> Assuming that normal linking of B to A does not work (e.g. if B is
> trapping exits, does not accept an exit message in the waiting state,
> and you can't change the code of A and B), you could spawn a small
> simple watchdog process, and link it to both A and B. It should wait
> for the termination of either of them. If A dies, the watchdog kills
> B by brute force, i.e., exit(B, kill). If B dies, the watchdog dies
> with it, quietly.

Apologies to all!

There was an error in my example. gen_server does indeed do the right
thing in this case. The problem occurs in this code:

loopB(PidA, S) ->
Res = (catch gen_server:call(PidA, {op, stuff})),
S1 = process(Res, S),
loopB(PidA, S1).

Here the gen_server:call catches the {'EXIT', Reason} signal from the
dying B process and turns it into a call to exit(Reason).

process B just gets an {'EXIT', Reason} result to the call, but it
doesn't know if Process A is still alive (there can be several
reasons for the {'EXIT', Reason}.

One fix might be for gen:call() to issue another exit signal towards
the calling process after returning the result.

Sean



_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
klacke
Posted: Wed Jan 24, 2007 6:58 pm Reply with quote
User Joined: 28 Feb 2005 Posts: 138
Sean Hinde wrote:

>
> One fix might be for gen:call() to issue another exit signal towards
> the calling process after returning the result.
>

Uhhh I wonder how much code would break by that. Quite a lot.

-klacke
_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
View user's profile Send private message AIM Address MSN Messenger
Guest
Posted: Wed Jan 24, 2007 7:05 pm Reply with quote
Guest
On 24 Jan 2007, at 18:50, Claes Wikstrom wrote:

> Sean Hinde wrote:
>
>> One fix might be for gen:call() to issue another exit signal
>> towards the calling process after returning the result.
>
> Uhhh I wonder how much code would break by that. Quite a lot.

Are you sure? The two processes are linked, so presumably the caller
wants to receive exit signals. Indeed the caller will always receive
an 'EXIT' signal whenever the linked process dies, *except* if it
dies while handling a call from the caller which is wrapped in a catch.

Seems to me that if there is a backwards compatibilty issue, it is
that other bugs are hidden by this behaviour which are just waiting
to happen.

Sean



>
> -klacke

_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
mats
Posted: Thu Jan 25, 2007 8:29 am Reply with quote
User Joined: 28 Feb 2005 Posts: 168 Location: budapest,hungary
Sean Hinde wrote:
>
> There was an error in my example. gen_server does indeed do the right
> thing in this case. The problem occurs in this code:
>
> loopB(PidA, S) ->
> Res = (catch gen_server:call(PidA, {op, stuff})),
> S1 = process(Res, S),
> loopB(PidA, S1).

> Here the gen_server:call catches the {'EXIT', Reason} signal from the
> dying B process and turns it into a call to exit(Reason).
>
> process B just gets an {'EXIT', Reason} result to the call, but it
> doesn't know if Process A is still alive (there can be several
> reasons for the {'EXIT', Reason}.

> One fix might be for gen:call() to issue another exit signal towards
> the calling process after returning the result.

surely if you catch the exit and it turns out you really wanted it, you
should re-throw?

how about

try
Res = gen_server:call(PidA, {op, stuff}),
S1 = process(Res, S),
loopB(PidA, S1)
catch
C:R ->
case is_process_alive(PidA) of
true -> loopB(PidA,dosomething({C,R},S));
false -> exit({C,R})
end
end


mats
_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
View user's profile Send private message MSN Messenger
Guest
Posted: Thu Jan 25, 2007 11:53 am Reply with quote
Guest
On 25 Jan 2007, at 08:23, Mats Cronqvist wrote:

> Sean Hinde wrote:
>>
>> One fix might be for gen:call() to issue another exit signal towards
>> the calling process after returning the result.
>
> surely if you catch the exit and it turns out you really wanted
> it, you
> should re-throw?
>
> how about
>
> try
> Res = gen_server:call(PidA, {op, stuff}),
> S1 = process(Res, S),
> loopB(PidA, S1)
> catch
> C:R ->
> case is_process_alive(PidA) of
> true -> loopB(PidA,dosomething({C,R},S));
> false -> exit({C,R})
> end
> end

This would work, but my is it ugly - how is anyone supposed to
remember to do that every time they want to be sure that the called
process has gone down (as opposed to any other reason for the call to
thrown an exception).

The problem as I see it is that the calling process only sometimes
get its 'EXIT' message - it depends on context.

Sean



_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
mats
Posted: Thu Jan 25, 2007 12:15 pm Reply with quote
User Joined: 28 Feb 2005 Posts: 168 Location: budapest,hungary
Sean Hinde wrote:
>
> On 25 Jan 2007, at 08:23, Mats Cronqvist wrote:
>
>> Sean Hinde wrote:
>>>
>>> One fix might be for gen:call() to issue another exit signal towards
>>> the calling process after returning the result.
>>
>> surely if you catch the exit and it turns out you really wanted it,
>> you
>> should re-throw?
>>
>> how about
>>
>> try
>> Res = gen_server:call(PidA, {op, stuff}),
>> S1 = process(Res, S),
>> loopB(PidA, S1)
>> catch
>> C:R ->
>> case is_process_alive(PidA) of
>> true -> loopB(PidA,dosomething({C,R},S));
>> false -> exit({C,R})
>> end
>> end
>
> This would work, but my is it ugly -

hey! it took me several seconds to write that code! some respect please :>

> how is anyone supposed to remember
> to do that every time they want to be sure that the called process has
> gone down (as opposed to any other reason for the call to thrown an
> exception).
>
> The problem as I see it is that the calling process only sometimes get
> its 'EXIT' message - it depends on context.

but it does get it's exit message. always. the "context" is that you catch it
and throw it away...

mats

p.s. i wonder if C and R above (the exception class and reason) will give you
enough info the distinguish a dead server from other causes of exits.
maybe it ought to be something like this;

try gen_server:call(PidA, {op, stuff}) of
Res -> loopB(PidA, process(Res, S))
catch
exit:{no_proc,_} -> exit(server_was_dead_when_we_called);
exit:insert_correct_value -> exit(server_died_while_processing);
C:R -> loopB(PidA,handle_other_errors({C,R},S))
end

the 4 branches here are unavoidable, i think, since there are 4 different
outcomes to the gen_server call.
_______________________________________________
erlang-questions mailing list
erlang-questions@erlang.org
http://www.erlang.org/mailman/listinfo/erlang-questions
Post recived from mailinglist
View user's profile Send private message MSN Messenger

Display posts from previous:  

All times are GMT
Page 1 of 2
Goto page 1, 2  Next
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum