Search code examples
servererlangtimeouterlang-otp

How to trigger handle_info due to timeout in erlang?


I am using a gen_server behaviour and trying to understand how can handle_info/2 be triggered from a timeout occurring in a handle_call for example:

-module(server).
-export([init/1,handle_call/3,handle_info/2,terminate/2).
-export([start/0,stop/0]).

init(Data)->
    {ok,33}.
start()->
   gen_server:start_link(?MODULE,?MODULE,[]).
stop(Pid)->
   gen_server:stop(Pid).

handle_call(Request,From,State)->
     Return={reply,State,State,5000},
     Return.

handle_info(Request,State)->
    {stop,Reason,State}.

terminate(Reason,State)->
    {ok,S}=file:file_open("D:/Erlang/Supervisor/err.txt",[read,write]),
    io:format(S,"~s~n",[Reason]),
    ok.

What i want to do:

I was expecting that if I launch the server and would not use gen_server:call/2 for 5 seconds (in my case) then handle_info would be called, which would in turn issue the stop thus calling terminate. I see it does not happen this way, in fact handle_info is not called at all.

In examples such as this i see the timeout is set in the return of init/1.

What I can deduce is that it handle_info gets triggered only if I initialize the server and issue nothing (nor cast nor call for N seconds).If so why I can provide Timeout in the return of both handle_cast/2 and handle_call/3 ?

Update:

I was trying to get the following functionality:

  1. If no call is issued in X seconds trigger handle_info/2
  2. If no cast is issued in Y seconds trigger handle_info/2

I thought this timeouts can be set in the return of handle_call and handle_cast:

{reply,Reply,State,X} //for call
{noreply,State,Y}   //for cast

If not, when are those timeouts triggered since they are returns?


Solution

  • To initiate timeout handling from gen_server:handle_call/3 callback, this callback has to be called in the first place. Your Return={reply,State,State,5000}, is not executed at all.

    Instead, if you want to “launch the server and would not use gen_server:call/2 for 5 seconds then handle_info/2 would be called”, you might return {ok,State,Timeout} tuple from gen_server:init/1 callback.

    init(Data)->
        {ok,33,5000}.
    

    You cannot set the different timeouts for different calls and casts. As stated by Alexey Romanov in comments,

    Having different timeouts for different types of messages just isn’t something any gen_* behavior does and would have to be simulated by maintaining them inside state.


    If one returns {reply,State,Timeout} tuple from any handle_call/3/handle_cast/2, the timeout will be triggered if the mailbox of this process is empty after Timeout.