[erlang-questions] gen_statem and multiple timeout vs 1

Raimo Niskanen raimo+erlang-questions@REDACTED
Wed Oct 5 15:44:42 CEST 2016


On Tue, Oct 04, 2016 at 10:52:38PM -0500, Fred Hebert wrote:
> On 10/04, Vans S wrote:
> :
> >I did not consider this. This is truly problematic BUT would not the 
> >current way timeout works run into this same problem? So this should 
> >not affect allowing multiple timeouts vs a single timeout.
> 
> Right now what you can do if you manage your own timers is to cancel the 
> old ones or ignore them (you've got their refs so it's easy) and you can 
> set new ones right away. You can't do that however if you rely on the 
> return tuple of a state transition to do it, since that transition 
> cannot happen from a code_change callback.

To some extent this cat is already out of the box thanks to the gen_fsm
timeout that got inherited to gen_statem.  If such a timer is running and
there is a code change on the server, it may expire "earlier" than you
would like or rather suddenly you might have wanted this particular timeout
to be longer.

If this is a real problem you can set a flag in your Data to note that
there has been a code change, and then act differently when the timeout
comes, or change states to one that is aware of the possibility of an early
timeout.

I wonder how this affects my state_timeout proposal...
It has got the same corner case, and the same workarounds apply.

The same would apply to named_timeout, with the same workarounds,
but the more timers you do not control, the messier to work around,
I guess...

> 
> >Learning from that, I rather this be inside gen_statem. If its not, I 
> >would have no problem to write my own little timer library for 
> >cancel_timer+purging mailbox. 
> >
> 
> Usually the pattern I use is to write a short 'reset_<whatever>_timer' 
> function that returns its ref, and then I can track the ref in my state.

It may be a bit tricky to get it right, but it is educational.

The problem in writing a library for this is that there are some options
on both how to start a timer and how to cancel it, so a library would
either not get it right for everybody or would have to take very many
options to be right for everybody.

So this may be a good candidate for a do-it-as-you-want-it library module.

/ Raimo



> 
> I always found this fairly convenient to deal with things, and for 
> example, I mostly don't clean up timers very hard. I.e. you can make use 
> of the newer cancel_timer options for async returns with or without 
> info, and by matching on specific refs, I can just ignore timers that 
> are for events I know are no longer up for consideration and let them 
> disappear, and automatically can ignore a bunch of potential race 
> conditions (i.e. no mailbox cleanup, just ignore messages coming in)
> 
> This is also neat to avoid whatever blocking or synchronization that 
> could take place on timer management, but in some cases you may still 
> want to do that.
> 
> 
> >Since you are only in ONE state at a time, you automatically know if 
> >the timeout happened, it MUST correspond to the current state we are 
> >in. 
> >
> 
> Does it? Couldn't the timeout event have been postponed, and therefore 
> come from a prior state change? I believe so. There's no relationship 
> between an event being handled in a state and that event having been 
> sent in that state.
> 
> >Another option is to remove the timeout then. It just seems out of place to me.  
> >
> 
> At the two extremes are the positions that all timeout management is 
> manual, and that gen_statem is to replace full-on control of timeouts 
> people can do manually (with all the cancellation options and whatnot).
> 
> Those are the two extremes, and the current thing is where on the 
> gradient does the timeout implementation currently lie. So far it 
> appears to be a fairly minimal convenience factor. I'm just wondering if 
> it's worth pushing it further on the gradient of "emulating all the 
> flexibility of manual control."
> 
> >What is the use case of a single timeout with a UNIQUE EventContent?
> >
> 
> The current semantics are specific about one thing:
> 
>     Generates an event of event_type() timeout after this time (in 
>     milliseconds) unless another event arrives in which case this 
>     time-out is cancelled. Notice that a retried or inserted event 
>     counts like a new in this respect.
> 
> These timeouts are mostly used for one thing in my experience: tracking 
> inactivity of the state machine. gen_servers and gen_fsms have the same 
> one. The only pragmatic use case I've made of them were to give myself a 
> delay of N milliseconds before which it would be reasonable to send the 
> process in hibernation, GCing and compacting its memory at once, since 
> it had not received a message in that time otherwise.
> 
> All other timeouts I tend to manage by hand because I do not want them 
> to be interruptible by the arrival of other messages in the mailbox of 
> the process.
> 
> This is a very, very important detail! Those semantics are also a lot 
> trickier to handle by yourself (you'd need to put them in every clause) 
> than most other timers you could imagine using. This makes them a fairly 
> good idea to include in the OTP behaviours themselves, as opposed to 
> most other timer usages, IMO.
> 
> Regards,
> Fred.

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB



More information about the erlang-questions mailing list