'after' in gen_server
orbitz@REDACTED
orbitz@REDACTED
Fri Mar 24 04:24:17 CET 2006
The reason I don't like 1 that much is because my code looks something
like:
handle_cast({irc_connect, Nick}, #state{state=connecting, dict=Dict,
irclib=Irclib} = State) ->
% Do connect stuff
join_channels(Irclib, dict_proc:fetch(join_on_connect, Dict)),
{noreply, State#state{nick=Nick, state=idle}};
handle_cast({stop, _}, #state{state=connecting} = State) ->
{stop, stop, State};
handle_cast({irc_message, {_, "PONG", _}}, #state{state=pong,
pong_timeout=Ref} = State) ->
{ok, cancel} = timer:cancel(Ref),
{noreply, State#state{state=idle, pong_timeout=undefined}};
handle_cast(irc_closed, #state{irclib=Irclib} = State) ->
irc_lib:connect(Irclib),
{noreply, State#state{state=connecting}};
handle_cast({irc_message, {_, "PING", [Server]}}, #state{irclib=Irclib}
= State) ->
irc_lib:pong(Irclib, Server),
{noreply, State};
handle_cast({irc_message, {_, "KICK", [Channel, Nick, _]}},
#state{irclib=Irclib, nick=Nick} = State) ->
irc_lib:join(Irclib, Channel),
{noreply, State};
So it gets ugly to return a timeout in all of these places.
On Mar 23, 2006, at 10:01 PM, Rick Pettit wrote:
> On Thu, Mar 23, 2006 at 08:59:45PM -0500, orbitz@REDACTED wrote:
>> The only problem I have with that is it sounds very error prone. What
>> if I forget a timeout? The more callbacks i implement the uglier
>> it'll
>> get, won't it?
>
> The way I see it you have two options:
>
> 1) Use the gen_server behaviour and its timeout mechanism--this
> involves
> returning an additional timeout parameter from:
>
> Module:init/1
> Module:handle_call/3
> Module:handle_cast/2
> Module:handle_info/2
>
> You will service the idle timeout in Module:handle_info/2. This
> is pretty
> simple, IMO, but I agree it is overkill if you don't otherwise
> require a
> gen_server.
>
> 2) Don't use gen_server (or any OTP behaviour)--rewrite your process
> as
> a simple server with receive loop. Now that you have direct
> access to
> the receive loop, you can plug in your 'after' clause with idle
> timeout
> and deal with the server going idle there.
>
> If you insist on using a gen_server than I can't see the point in not
> going
> with (1)--anything else is going to require more server state, more
> code, and
> will ultimately be more error prone.
>
> -Rick
>
>> On Mar 23, 2006, at 4:35 PM, Rick Pettit wrote:
>>
>>> On Thu, Mar 23, 2006 at 04:26:22PM -0500, orbitz@REDACTED wrote:
>>>> I want to do it from all callbacks. Basically I want to make it so
>>>> if
>>>> the server is idle for X amount of time, then that means something
>>>> is
>>>> wrong and I need to do something to figure out what is wrong.
>>>
>>> Then have your callbacks set a gen_server "idle timeout" by way of
>>> the
>>> gen_server timeout mechanism, and service timeouts in handle_info/2.
>>>
>>> It is as simple as passing a timeout value in the return value from
>>> your
>>> callbacks--Module:init/1, Module:handle_call/3, Module:handle_cast/2,
>>> etc.
>>>
>>> -Rick
>>>
>>>> On Mar 23, 2006, at 11:04 AM, Rick Pettit wrote:
>>>>
>>>>> On Thu, Mar 23, 2006 at 10:42:04AM -0500, orbitz@REDACTED wrote:
>>>>>> I am reworking a bit of code into gen_server pattern. In this
>>>>>> code
>>>>>> I
>>>>>> have a typical loop construct. In this I want to perform an
>>>>>> action
>>>>>> if
>>>>>> no messages have been receive in a certain amount of time, to do
>>>>>> this
>>>>>> I
>>>>>> simply have after sometimeout ->. Is there any equivalence of
>>>>>> this
>>>>>> in
>>>>>> gen_server?
>>>>>
>>>>> If I understand you correctly, all you need to do is set a timeout
>>>>> when
>>>>> returning from one of the gen_server callback functions.
>>>>>
>>>>> For example, instead of returning {ok,State} from Module:init/1,
>>>>> return
>>>>> {ok,State,TimeoutMs}. You can do this for all the gen_server
>>>>> callback
>>>>> routines (at least handle_call/handle_cast, etc).
>>>>>
>>>>> This effectively sets a timer which will expire if no message is
>>>>> received
>>>>> by the gen_server before TimeoutMs has elapsed. If/when the timer
>>>>> does
>>>>> expire, you receive a 'timeout' message in Module:handle_info/2.
>>>>>
>>>>> -Rick
>>>>>
>>>>> P.S. Since gen_server abstracts the server receive loop, I (as a
>>>>> general rule
>>>>> of thumb) *never* call receive in a gen_server callback module.
>>>>>
>>>>>> It has been suggested that I use a timer and record when the last
>>>>>> message has come in and when the timer signals check against that
>>>>>> message. This seems a poor solution. Another suggestions was to
>>>>>> use
>>>>>> a
>>>>>> gen_fsm with a timeout, but this seem a bit much just to get an
>>>>>> 'after'
>>>>>> mechanism. Any other suggestions? Perhaps my disregard of gen_fsm
>>>>>> is
>>>>>> a
>>>>>> bit hasty?
>>>>>
>>>>
>>>
>>
>
More information about the erlang-questions
mailing list