SV: Trouble with gen_server
Richard Cameron
camster@REDACTED
Tue Mar 28 20:36:01 CEST 2006
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20060328/4c2f7489/attachment.htm>
More information about the erlang-questions
mailing list