SV: Trouble with gen_server
Mark Lee
mark@REDACTED
Wed Mar 29 10:57:20 CEST 2006
Bingo!
The bit I've been missing: catch,
thanks very much,
Mark
On Tue, Mar 28, 2006 at 07:36:01PM +0100, Richard Cameron wrote:
>
> On 28 Mar 2006, at 15:41, mark@REDACTED wrote:
>
> >Ok, me being daft there. So how can I handle the timeout? I don't want
> >the gen_server to die when the call exceeds the timeout, I just
> >want to
> >be able to reflect that this has happened.
>
> Have a look at this:
>
> -module(s).
> -compile(export_all).
> -define(SERVER,srv).
>
> start() -> gen_server:start({local,?SERVER}, ?MODULE, [], []).
> start_link() -> gen_server:start_link({local,?SERVER}, ?MODULE, [], []).
> fail() -> gen_server:call(?SERVER, slowcall, 1).
> safe() -> case catch fail() of
> {'EXIT', Reason} -> {error, Reason};
> Other -> {ok, Other}
> end.
>
> init([]) -> {ok, []}.
> handle_call(slowcall,_,State) ->
> receive after 100 -> x end,
> {reply, ok, State}.
>
>
> There are a few ways of running it. Here's what you were doing:
>
> Eshell V5.4.13 (abort with ^G)
> 1> s:start_link().
> {ok,<0.37.0>}
> 2> s:fail().
> ** exited: {timeout,{gen_server,call,[srv,slowcall,1]}} **
> 3> s:fail().
> ** exited: {noproc,{gen_server,call,[srv,slowcall,1]}} **
>
> What's happening here is that you're using the shell to start your
> gen_server process. You end up linking the shell process to the
> gen_server process which means that if that the shell process dies,
> it takes down the gen_server with it. The default shell behaviour is
> that if it executes a function which fails, it exits and a new
> "replacement shell" process is spawned off to carry on. This is
> what's happening here. Your first call to s:fail() does just that -
> it fails. The gen_server was fine at that point... it didn't crash
> until it got brought down by the shell exiting (because the two
> processes are linked).
>
> Here's another way of running the example:
>
> 1> s:start().
> {ok,<0.37.0>}
> 2> s:fail().
> ** exited: {timeout,{gen_server,call,[srv,slowcall,1]}} **
> 3> s:fail().
> ** exited: {timeout,{gen_server,call,[srv,slowcall,1]}} **
>
> Again, the fail() function fails, but this time the shell process
> dying doesn't cause the gen_server to terminate. At the end of this
> example it's still alive and well and processing requests.
>
> Another way is this:
>
> Eshell V5.4.13 (abort with ^G)
> 1> s:start_link().
> {ok,<0.37.0>}
> 2> s:safe().
> {error,{timeout,{gen_server,call,[srv,slowcall,1]}}}
> 3> s:safe().
> {error,{timeout,{gen_server,call,[srv,slowcall,1]}}}
>
> This time, although the shell process is linked to the gen_server,
> I've caught the error from the fail() function and so the shell
> didn't exit. Thus, it didn't cause the gen_server to die.
>
>
> All three approaches are equally valid in different situations. Joe
> Armstrong's book (and his PhD thesis) gives examples of when you'd
> want to link processes together and when you wouldn't. Also, although
> there *is* a "catch" keyword in Erlang it's used surprisingly rarely.
> Catching all errors like this sometimes isn't actually terribly
> helpful, and it's certainly not something the language just makes you
> do to be awkward (religiously wrapping every possible things which
> could fail with a catch statement to prevent any knock-on effect for
> any processes linked to it - although I have seen Java programmers do
> things like this).
>
> You need to have a strategy of which processes should die if a call
> to the gen_server doesn't succeed. There could be instances where you
> return a "Sorry, system can't cope with the load at the moment" to
> the end user and press on regardless. On the other hand you might be
> talking about a realtime system where the gen_server can't and
> shouldn't take that long to reply. If that's the case then you'd
> probably want to ask the gen_server to crash (crashing is a _good_
> thing in Erlang), shutdown cleanly, and then arrange for it to be
> restarted (by a supervisor) to get it into a decent state in order to
> continue processing requests. This is the Erlang "let it crash"
> approach.
>
> The OTP design principles document is probably the best starting
> point for all this stuff:
>
> http://erlang.se/doc/doc-5.4.12/doc/design_principles/part_frame.html
>
> Richard.
>
> !DSPAM:442982a6199691251019417!
More information about the erlang-questions
mailing list