"Forwarding" of gen_server calls?
Jim Larson
jim@REDACTED
Fri Sep 17 02:02:21 CEST 1999
I'm using using open-source Erlang (erlang_base-47.4.1) on FreeBSD
2.2.8.
I'm writing a server S1 using the gen_server behaviour. One of
the handle_call() clauses makes a "tail call" to server S2 (which
also uses gen_server), i.e.
handle_call(Request, From, State) ->
%% ... some pre-processing goes on ...
Reply = gen_server:call(S2, Arg),
{reply, Reply, NewState}
However, the call to S2 may block for a long period of time, thus
blocking all calls to S1 in the interim.
What would be nice is a "tail call" function in the gen_server
package that would allows you to forward the From "continuation"
to another gen_server module, but returns to its caller immediately.
handle_call(Request, From, State) ->
%% ... the same pre-processing goes on ...
%% This call won't block
case gen_server:tail_call(S2, Arg, From) of
ok ->
{noreply, NewState}; % S2 will reply to our caller
{error, Reason} ->
%% error looking up S2
{reply, {error, SomeReason}, SomeState}
end.
The implementation for the simplest clause of tail_call would be
something like:
tail_call(Pid, Request, From) when pid(Pid), node(Pid) == node() ->
Pid ! {'$gen_call', From, Request},
ok.
[Okay, so it doesn't quite handle all error cases, since the original
gen_server caller will only catch 'EXIT' messages from the Pid of
the server it originally called. I'm sure there are ways to deal
with this.]
I realize that there are other workarounds, including:
- returning appropriate information from S1, and
allowing the original client process to call S2;
- having S1 spawn a new process to make the blocking call;
- explicitly passing the From "continuation" as an
argument to a special method of S2.
However, these workarounds are unappealing. Am I overlooking any
other options or existing infrastructure for accomplishing what I
want?
I await the comments of those wiser in the ways of Erlang than I.
Jim
More information about the erlang-questions
mailing list