Search code examples
erlangerlang-otpgen-servererlang-supervisor

gen_server , a server can’t call its own API functions?


When I read Erlang OTP Action book, I found this reminder on page 117:

With your RPC server, you can try calling any function exported from any module available on the server side, except one: your own tr_server:get_count/0. In general, a server can’t call its own API functions. Suppose you make a synchronous call to the same server from within one of the callback functions: for example, if handle_info/2 tries to use the get_count/0 API function. It will then perform a gen_server:call(...) to itself. But that request will be queued up until after the current call to handle_info/2 has finished, resulting in a circular wait—the server is deadlocked.

But I looked at the tr_server sample code :

get_count() ->
    gen_server:call(?SERVER, get_count).   

stop() ->
    gen_server:cast(?SERVER, stop).

handle_info({tcp, Socket, RawData}, State) ->                   
    do_rpc(Socket, RawData),
    RequestCount = State#state.request_count,
    {noreply, State#state{request_count = RequestCount + 1}};
......
do_rpc(Socket, RawData) ->
try
    {M, F, A} = split_out_mfa(RawData),
    Result = apply(M, F, A),  %  tr_server process -> handle_info -> do_rpc ->call & cast                                
    gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))       
catch
    _Class:Err ->
        gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
end.

I found the examples and cautions in the book inconsistent , the gen_server:call and gen_server:cast by tr_server process ownself. Am I misinterpreting this?


Solution

  • Calling gen_server:cast from within the server process is fine, because it is asynchronous: it adds the message to the mailbox of the process and then continues, returning ok. Only gen_server:call has this problem, because it makes the process wait for an answer from itself.