Search code examples
erlangerlang-otpgen-server

Why does gen_server get timeout


I am trying to figure out why my gen_server crashes with a timeout since i am treating all possible cases:

module(wk).
-behaviour(gen_server).
-compile(export_all).


-record(state,{
    limit,
    count=0,
    toSend
}).
start_link(ToSend,Limit)->
   gen_server:start_link(?MODULE, {ToSend,Limit}, []).



init({ToSend,Limit})->
    State=#state{toSend=ToSend,limit=Limit},
    {ok,State}.


handle_call({process,Message},From,State)->
    {reply,{processed,os:timestamp()},State};
handle_call(Message,From,State)->
    self() ! {from_call,Message},
    {noreply,State}.
handle_cast(Message,State=#state{count=C})->
    self() ! {from_cast,Message},
    {noreply,State}.

handle_info(Message,State=#state{count=C,limit=L,toSend=T})->
    io:format("inside handle_info"),
    T! {badrequest,Message},
    Ret=if C>L -> {stop,State};
           _ ->{noreply,State#state{count=C+1}}
        end,
    Ret.

As you can see this server can handles a number of limit unknown messages , and as well as cast messages. Now my problem is with the handle_call:

  • If i send a message that fits the first case its ok and it replies back
  • When i send an unknown message using gen_server:call(S,xx) for example, i get a timeout error :

    exception exit: {timeout,{gen_server,call,[<0.102.0>,33]}} in function gen_server:call/2 (gen_server.erl, line 215)

Why is my server timing out ? I can see that after handle_call it enters into handle_info but why does it crash ?

Usage:

{ok,Y}=wk:start_link(self(),3).
 gen_server:cast(Y,some_message).  % works limit times and then crashes as expected
 Y ! some_message % works limit times and then crashes as expected
 gen_server:call(Y,some_message) % gets inside handle_info , since i get the io message, then times out

Solution

  • Why is my server timing out ?

    From the gen_server:call() docs:

    call(ServerRef, Request) -> Reply
    call(ServerRef, Request, Timeout) -> Reply
    

    Makes a synchronous call to the ServerRef of the gen_server process by sending a request and waiting until a reply arrives or a time-out occurs.
    ...
    ...

    Timeout is an integer greater than zero that specifies how many milliseconds to wait for a reply, or the atom infinity to wait indefinitely. Defaults to 5000. If no reply is received within the specified time, the function call fails.

    Because you chose to return {noreply...} in your handle_call() function, gen_server:call() cannot return and times out after 5 seconds. You need to manually call gen_server:reply/2 (in another process) to send a reply back to the client before the timeout.