[erlang-questions] gen_statem and multiple timeout vs 1

Vans S <>
Tue Oct 4 22:51:19 CEST 2016


> I'd rather see this implemented by seeing one track the timers they use 
> (with their Refs), and their action from the message is dependent on 
> their state (halted or auto_attacking). What you're advocating is doing 
> that tracking by hand based on some other unrelated state, and you're 
> actively fighting one of the states that could exist in your FSM!
> 
> At the very least, that sounds better than adding yet more features into 
> the gen_statem behaviour, which is gathering requirements at a fairly 
> rapid rate so far.

A NFA Nondeterministic finite automaton - Wikipedia, the free encyclopedia by definition is a state machine that can be in multiple states simultaneously.

Do we really need a gen_statem_nfa module now?

>From a basic use case of a connection that needs to send keep alives at regular intervals.  This "unnecessary feature" is screaming include me.
To be clear the connection has 2 timers, timer 1 is if there has not been a message received in x amount of time. Timer 2 is the "when to send keep alive" timer.

If a packet arrives on the connection, we bump the keep-alive timer since we know the peer is alive.  This is a pretty basic feature.
And being able to bump the keep-alive time this way will require keeping timer refs and using cancel_timer + purging mailbox.

Its the natural way you want to write the gen_statem behavior. At least IMO.



This single state way does not work, it works in simple use cases like a safe/lock or basic phone call. But it
does not work in more complex applications.

The individual states could be running, jumping and attacking. Do you really want to write a combo state for each occurrence?

moving, attacking, jumping, stopped, moving_attacking, moving_attacking_jumping, attacking_jumping, moving_jumping, jumping_stopped, .. etc

>From what your saying, the state machine needs to be in ONLY ONE of these states at a time.


> This is a state machine behaviour! If you're buffed, this should be 
> represented in your state explicitly rather than implicitly within the 
> state machine mechanisms!

This is true.  But then there needs to be a way to get the timer ref.  Sometimes Erlangs approach is, just make it work.  
I don't see any way to get the timer ref without including it in the callback OR creating your own timer and including it for tracking (vs just specifying the timeout).


> Think for example that you upgrade a node's code. One thing to consider 
> is that after the upgrade you may add or remove timers. 

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.

 > Hell, you could even start a related 
> 'timeout' FSM that sends message at specific intervals to your own FSM 
> and manage that one

I tried this way before and it was not very performant.  Sending a timeout every 100ms and managing tons of other timers in that timeout
was very poor performance.  The reason is I needed acceptable latency and did not want to deal with cancel_timer. Changing to gen_statem timeout dropped the 16 phys core (with 200k erlang processes) cpu usage from 50% to 0-1%.

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. 



Either way to me having 1 timeout that can proc a UNIQUE EventContent is silly. It should be fixed then. A timeout ONLY procs a timeout event, this way
you wont accidentally override the timeout EventContent.

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. 

Another option is to remove the timeout then. It just seems out of place to me.  

What is the use case of a single timeout with a UNIQUE EventContent? 

Its not to allow the gen_statem to tick itself, (which gen_event lacked) if it was there would not be a way to pass a unique EventContent.

Unique event content is misleading making you think if you pass a different EventContent, it will NOT override a previous EventContent.

 

    On Tuesday, October 4, 2016 3:39 PM, Fred Hebert <> wrote:
 

 On 10/04, Vans S wrote:
>Picture a game where you autoattack every 1000ms, if you use Halt 
>command your autoattack stops and movement stops.
>The return will look like [{named_timeout, infinity, 
>auto_attack}, {named_timeout, infinity, move}].  In this case if we 
>were not autoattacking butmoving and halted we would crash. Which is 
>bad.  It adds unneeded complexity.
>

I'd rather see this implemented by seeing one track the timers they use 
(with their Refs), and their action from the message is dependent on 
their state (halted or auto_attacking). What you're advocating is doing 
that tracking by hand based on some other unrelated state, and you're 
actively fighting one of the states that could exist in your FSM!

At the very least, that sounds better than adding yet more features into 
the gen_statem behaviour, which is gathering requirements at a fairly 
rapid rate so far.

>
>For example, if we have a moral boost buff that lasts 10,000ms, and we receive another 10,000ms moral boost buff that stacks, we want to increment 
>the current 10,000ms moral_buff timeout by 10,000ms more.  Maybe on named_timeout callback pass the list of all Timers registered, or at least [{Name, TimeRemaining}] ?
>

This is a state machine behaviour! If you're buffed, this should be 
represented in your state explicitly rather than implicitly within the 
state machine mechanisms!

Think for example that you upgrade a node's code. One thing to consider 
is that after the upgrade you may add or remove timers. However, the 
code change mechanism does not allow you to manage that kind of stuff: 
you can only modify your own state and data, but not play with the event 
mailbox.

To be able to change your logic around timeouts during a pause would 
require you to move them to your own FSM's data and to ignore old 
references, no way around it.

There's a benefit to handling that kind of stuff explicitly, and if 
timers are integral to your system progressing, you should probably take 
a more direct approach to it. Hell, you could even start a related 
'timeout' FSM that sends message at specific intervals to your own FSM 
and manage that one, rather than doing it all through the more 
restrictive interface.



   
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20161004/64a1998a/attachment.html>


More information about the erlang-questions mailing list