[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