gen_statem confusion

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
19 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

gen_statem confusion

Vans S
What is the correct way to have an event proc next in the queue before any
other events/actions are procced.  Meaning this event should come before
any send / cast / call that were inserted into the process mailbox WHILE the
event was being handled.

The options seem to be returning a timeout of 0 or returning next_event.

It is confusing which one is correct to use to get the desired behavior.

Example:

handle_event(timeout, _, _, _) ->
    long_running_func(),
    %a proc sends to us send(self(), msg)
    {next_event, internal, next_state},
    %OR

    {next_state, next_state, no_data, 0}.

We want to proc the next_state event/timeout befor handing the msg msg we got
from a random process.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Fred Hebert-2
On 01/18, Vans S wrote:

>Example:
>
>handle_event(timeout, _, _, _) ->
>    long_running_func(),
>    %a proc sends to us send(self(), msg)
>    {next_event, internal, next_state},
>    %OR
>
>    {next_state, next_state, no_data, 0}.
>
>We want to proc the next_state event/timeout befor handing the msg msg
>we got
>from a random process.

The {next_state, StateName, Data, Actions} form allows `Actions' to be
one or more of:

- `postpone', which will replay the current event on the next state
  transition and skip it for now. This one has to do with replicating a
  selective receive
- `{next_event, EventType, EventContent}', which will enqueue the
  generated event as the next one to run no matter what, unless other
  events were already enqueued with the {next_event, ...} action
  beforehand. This is a mechanism to allow self-driving state machines
  with event injection without losing the ability to trace or handle
  calls from the sys module (i.e. the state machine does not become
  unresponsive)
- 'enter action' events, related to handling state transitions. Those
  include timeouts (generate a message if no event has been received in
  a while), state timeouts (generate a message if no state transition
  has happened in a while), and asking for hibernation. Those have to do
  with handling the behaviour of the process between events or state
  transitions.
- replying to a process that has previously sent a synchronous call

So if you want the next event run internally to be 'next_state' (which I
assume means "progress to the next state" in your state machine), you'd
need to return:

handle_event(timeout, _TimeoutMsg, StateName, Data) ->
    ...
    {next_state, StateName, Data, [{next_event, internal, next_state}]}.

which will enqueue 'next_state' as an internally-generated message to be
handled.

Regards,
Fred.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
Thanks for the detailed response I will try it this way. What I want to do is progress through a chain of states
without processing any messages in between, and once the final state is reached to start processing messages normally.



On Wednesday, January 18, 2017 2:20 PM, Fred Hebert <[hidden email]> wrote:
On 01/18, Vans S wrote:

>Example:
>
>handle_event(timeout, _, _, _) ->
>    long_running_func(),
>    %a proc sends to us send(self(), msg)
>    {next_event, internal, next_state},
>    %OR
>
>    {next_state, next_state, no_data, 0}.
>
>We want to proc the next_state event/timeout befor handing the msg msg
>we got
>from a random process.

The {next_state, StateName, Data, Actions} form allows `Actions' to be
one or more of:

- `postpone', which will replay the current event on the next state
  transition and skip it for now. This one has to do with replicating a
  selective receive
- `{next_event, EventType, EventContent}', which will enqueue the
  generated event as the next one to run no matter what, unless other
  events were already enqueued with the {next_event, ...} action
  beforehand. This is a mechanism to allow self-driving state machines
  with event injection without losing the ability to trace or handle
  calls from the sys module (i.e. the state machine does not become
  unresponsive)
- 'enter action' events, related to handling state transitions. Those
  include timeouts (generate a message if no event has been received in
  a while), state timeouts (generate a message if no state transition
  has happened in a while), and asking for hibernation. Those have to do
  with handling the behaviour of the process between events or state
  transitions.
- replying to a process that has previously sent a synchronous call

So if you want the next event run internally to be 'next_state' (which I
assume means "progress to the next state" in your state machine), you'd
need to return:

handle_event(timeout, _TimeoutMsg, StateName, Data) ->
    ...
    {next_state, StateName, Data, [{next_event, internal, next_state}]}.

which will enqueue 'next_state' as an internally-generated message to be

handled.

Regards,
Fred.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Kenneth Lakin
In reply to this post by Fred Hebert-2
On 01/18/2017 11:20 AM, Fred Hebert wrote:

> So if you want the next event run internally to be 'next_state' (which I
> assume means "progress to the next state" in your state machine), you'd
> need to return:
>
> handle_event(timeout, _TimeoutMsg, StateName, Data) ->
>    ...
>    {next_state, StateName, Data, [{next_event, internal, next_state}]}.
>
> which will enqueue 'next_state' as an internally-generated message
> to be handled.
You need to be a little careful with this. next_event is a _stack_, not
a queue. If you return

{next_state, state, Data, [{next_event, internal, a}, {next_event,
internal, b}]}

and then in state(internal, a, Data) you return

{next_state, state, Data, [{next_event, internal, c}, {next_event,
internal, d}]}

The next three calls (assuming nothing else is pushed on the next_event
stack) will be
state(internal, c, Data)
state(internal, d, Data)
state(internal, b, Data)

It's really easy to overlook this. This subtle quirk was the cause of at
least one bug in a _widely_ used library.



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Fred Hebert-2
On 01/18, Kenneth Lakin wrote:
>You need to be a little careful with this. next_event is a _stack_, not
>a queue. [...] It's really easy to overlook this. This subtle quirk was
>the cause of at least one bug in a _widely_ used library.

Specifically I copied the terminology from the docs at
http://erlang.org/doc/man/gen_statem.html#type-action :

> The stored events are inserted in the queue as the next to process
> before any already queued events. The order of these stored events is
> preserved, so the first next_event in the containing list becomes the
> first to process.

I guess that could use some rewording.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
Would using a timeout or state_timeout of 0 provide the same guarantees as using next_event?
Looking at the API it seems state_timeout maybe just shortform for {next_event, state_timeout, ..}



On Wednesday, January 18, 2017 3:48 PM, Fred Hebert <[hidden email]> wrote:
On 01/18, Kenneth Lakin wrote:
>You need to be a little careful with this. next_event is a _stack_, not
>a queue. [...] It's really easy to overlook this. This subtle quirk was
>the cause of at least one bug in a _widely_ used library.

Specifically I copied the terminology from the docs at
http://erlang.org/doc/man/gen_statem.html#type-action :

> The stored events are inserted in the queue as the next to process
> before any already queued events. The order of these stored events is
> preserved, so the first next_event in the containing list becomes the
> first to process.

I guess that could use some rewording.

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Kenneth Lakin
In reply to this post by Fred Hebert-2
On 01/18/2017 12:48 PM, Fred Hebert wrote:
> Specifically I copied the terminology from the docs at
> http://erlang.org/doc/man/gen_statem.html#type-action :

<snip>

> I guess that could use some rewording.

Yeah, the gen_statem documentation has some significantly rough patches.
(Insert standard "good documentation is hard and often boring work, and
anyone who volunteers to write accurate documentation that's even
vaguely legible is a minor hero" disclaimer here.)




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Fred Hebert-2
In reply to this post by Vans S
On 01/18, Vans S wrote:
>Would using a timeout or state_timeout of 0 provide the same guarantees as using next_event?
>Looking at the API it seems state_timeout maybe just shortform for {next_event, state_timeout, ..}
>
No.

A regular timeout would not trigger if messages are received or waiting
in the mailbox

A next_event timeout works as follows according to the docs.

>  If the value is 0 no timer is actually started, instead the the
>  time-out event is enqueued to ensure that it gets processed before
>  any not yet received external event.

Already received external events and enqueued next_events will likely
run before state timeouts.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S


This wording is really confusing:

> instead the the time-out event is enqueued to ensure
> that it gets processed before any not yet received
> external event
Because when I tried a test case

init() ->
  send(self(), hi),
  {_,_,_,0}.  %0 timeout basically

The 0 timeout procced before the 'hi' message.
Using 1 as the timeout, 'hi' message procs first.

But it says not yet received external event.  To me send() seems like
an external event. Hence confusing.





On Wednesday, January 18, 2017 7:27 PM, Fred Hebert <[hidden email]> wrote:
On 01/18, Vans S wrote:

>Would using a timeout or state_timeout of 0 provide the same guarantees as using next_event?
>Looking at the API it seems state_timeout maybe just shortform for {next_event, state_timeout, ..}
>
No.

A regular timeout would not trigger if messages are received or waiting
in the mailbox

A next_event timeout works as follows according to the docs.

>  If the value is 0 no timer is actually started, instead the the
>  time-out event is enqueued to ensure that it gets processed before
>  any not yet received external event.

Already received external events and enqueued next_events will likely
run before state timeouts.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Alex S.

> 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
>
>
>
> This wording is really confusing:
>
>> instead the the time-out event is enqueued to ensure
>> that it gets processed before any not yet received
>> external event
> Because when I tried a test case
>
> init() ->
>  send(self(), hi),
>  {_,_,_,0}.  %0 timeout basically
>
> The 0 timeout procced before the 'hi' message.
> Using 1 as the timeout, 'hi' message procs first.
>
> But it says not yet received external event.  To me send() seems like
> an external event. Hence confusing.
Well, it was sent, but not yet received by the gen_statem’s main loop.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Raimo Niskanen-2
On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:

>
> > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> >
> >
> >
> > This wording is really confusing:
> >
> >> instead the the time-out event is enqueued to ensure
> >> that it gets processed before any not yet received
> >> external event
> > Because when I tried a test case
> >
> > init() ->
> >  send(self(), hi),
> >  {_,_,_,0}.  %0 timeout basically
> >
> > The 0 timeout procced before the 'hi' message.
> > Using 1 as the timeout, 'hi' message procs first.
> >
> > But it says not yet received external event.  To me send() seems like
> > an external event. Hence confusing.
> Well, it was sent, but not yet received by the gen_statem’s main loop.

Perfectly correct.

While gen_statem processes enqueued events it is guaranteed to not enter a
receive statement, so no new messages are received until after ther
state_timeout 0 message.

Other enqueued messages that are being processed such as next_event
messages will be processed before a state_timeout 0 message.

So if you in a state callback insert more next_event messages these are
inserted first in the queue, and a state_timeout 0 message is inserted last
in the queue.
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Raimo Niskanen-2
In reply to this post by Kenneth Lakin
On Wed, Jan 18, 2017 at 02:18:23PM -0800, Kenneth Lakin wrote:

> On 01/18/2017 12:48 PM, Fred Hebert wrote:
> > Specifically I copied the terminology from the docs at
> > http://erlang.org/doc/man/gen_statem.html#type-action :
>
> <snip>
>
> > I guess that could use some rewording.
>
> Yeah, the gen_statem documentation has some significantly rough patches.
> (Insert standard "good documentation is hard and often boring work, and
> anyone who volunteers to write accurate documentation that's even
> vaguely legible is a minor hero" disclaimer here.)

Contributions are welcome ;-)

(I do not remember how many times I have tried to rewrite
 that particular paragraph)

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
In reply to this post by Raimo Niskanen-2
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
Also is there a priority such as external, internal, timeout, state_timeout, etc?

Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
is called.




On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:

>
> > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> >
> >
> >
> > This wording is really confusing:
> >
> >> instead the the time-out event is enqueued to ensure
> >> that it gets processed before any not yet received
> >> external event
> > Because when I tried a test case
> >
> > init() ->
> >  send(self(), hi),
> >  {_,_,_,0}.  %0 timeout basically
> >
> > The 0 timeout procced before the 'hi' message.
> > Using 1 as the timeout, 'hi' message procs first.
> >
> > But it says not yet received external event.  To me send() seems like
> > an external event. Hence confusing.
> Well, it was sent, but not yet received by the gen_statem’s main loop.

Perfectly correct.

While gen_statem processes enqueued events it is guaranteed to not enter a
receive statement, so no new messages are received until after ther
state_timeout 0 message.

Other enqueued messages that are being processed such as next_event
messages will be processed before a state_timeout 0 message.

So if you in a state callback insert more next_event messages these are
inserted first in the queue, and a state_timeout 0 message is inserted last
in the queue.
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
Actually I jumped the gun here:


using a state_timeout as next event which is a valid
event_type() as said in the docs produces:

** Reason for termination = error:{bad_action_from_state_function,
{next_event,state_timeout,hi}}
So state_timeout cant be used here.

timeout,  cast, info can be used.

{call, pid()} also cant be used.



On Thursday, January 19, 2017 11:01 AM, Vans S <[hidden email]> wrote:
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
Also is there a priority such as external, internal, timeout, state_timeout, etc?

Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
is called.





On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:

>
> > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> >
> >
> >
> > This wording is really confusing:
> >
> >> instead the the time-out event is enqueued to ensure
> >> that it gets processed before any not yet received
> >> external event
> > Because when I tried a test case
> >
> > init() ->
> >  send(self(), hi),
> >  {_,_,_,0}.  %0 timeout basically
> >
> > The 0 timeout procced before the 'hi' message.
> > Using 1 as the timeout, 'hi' message procs first.
> >
> > But it says not yet received external event.  To me send() seems like
> > an external event. Hence confusing.
> Well, it was sent, but not yet received by the gen_statem’s main loop.

Perfectly correct.

While gen_statem processes enqueued events it is guaranteed to not enter a
receive statement, so no new messages are received until after ther
state_timeout 0 message.

Other enqueued messages that are being processed such as next_event
messages will be processed before a state_timeout 0 message.

So if you in a state callback insert more next_event messages these are
inserted first in the queue, and a state_timeout 0 message is inserted last
in the queue.
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
Yea ignore that. That is because I was not up to R19.2 when I tested.
Let me get up to date.



On Thursday, January 19, 2017 11:08 AM, Vans S <[hidden email]> wrote:
Actually I jumped the gun here:


using a state_timeout as next event which is a valid
event_type() as said in the docs produces:

** Reason for termination = error:{bad_action_from_state_function,
{next_event,state_timeout,hi}}
So state_timeout cant be used here.

timeout,  cast, info can be used.

{call, pid()} also cant be used.




On Thursday, January 19, 2017 11:01 AM, Vans S <[hidden email]> wrote:
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
Also is there a priority such as external, internal, timeout, state_timeout, etc?

Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
is called.





On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:

>
> > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> >
> >
> >
> > This wording is really confusing:
> >
> >> instead the the time-out event is enqueued to ensure
> >> that it gets processed before any not yet received
> >> external event
> > Because when I tried a test case
> >
> > init() ->
> >  send(self(), hi),
> >  {_,_,_,0}.  %0 timeout basically
> >
> > The 0 timeout procced before the 'hi' message.
> > Using 1 as the timeout, 'hi' message procs first.
> >
> > But it says not yet received external event.  To me send() seems like
> > an external event. Hence confusing.
> Well, it was sent, but not yet received by the gen_statem’s main loop.

Perfectly correct.

While gen_statem processes enqueued events it is guaranteed to not enter a
receive statement, so no new messages are received until after ther
state_timeout 0 message.

Other enqueued messages that are being processed such as next_event
messages will be processed before a state_timeout 0 message.

So if you in a state callback insert more next_event messages these are
inserted first in the queue, and a state_timeout 0 message is inserted last
in the queue.
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
Okay same problem with R19.2.1



On Thursday, January 19, 2017 11:15 AM, Vans S <[hidden email]> wrote:
Yea ignore that. That is because I was not up to R19.2 when I tested.
Let me get up to date.




On Thursday, January 19, 2017 11:08 AM, Vans S <[hidden email]> wrote:
Actually I jumped the gun here:


using a state_timeout as next event which is a valid
event_type() as said in the docs produces:

** Reason for termination = error:{bad_action_from_state_function,
{next_event,state_timeout,hi}}
So state_timeout cant be used here.

timeout,  cast, info can be used.

{call, pid()} also cant be used.




On Thursday, January 19, 2017 11:01 AM, Vans S <[hidden email]> wrote:
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
Also is there a priority such as external, internal, timeout, state_timeout, etc?

Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
is called.





On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:

>
> > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> >
> >
> >
> > This wording is really confusing:
> >
> >> instead the the time-out event is enqueued to ensure
> >> that it gets processed before any not yet received
> >> external event
> > Because when I tried a test case
> >
> > init() ->
> >  send(self(), hi),
> >  {_,_,_,0}.  %0 timeout basically
> >
> > The 0 timeout procced before the 'hi' message.
> > Using 1 as the timeout, 'hi' message procs first.
> >
> > But it says not yet received external event.  To me send() seems like
> > an external event. Hence confusing.
> Well, it was sent, but not yet received by the gen_statem’s main loop.

Perfectly correct.

While gen_statem processes enqueued events it is guaranteed to not enter a
receive statement, so no new messages are received until after ther
state_timeout 0 message.

Other enqueued messages that are being processed such as next_event
messages will be processed before a state_timeout 0 message.

So if you in a state callback insert more next_event messages these are
inserted first in the queue, and a state_timeout 0 message is inserted last
in the queue.
--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Raimo Niskanen-2
On Thu, Jan 19, 2017 at 04:35:19PM +0000, Vans S wrote:

> Okay same problem with R19.2.1
>
>
>
> On Thursday, January 19, 2017 11:15 AM, Vans S <[hidden email]> wrote:
> Yea ignore that. That is because I was not up to R19.2 when I tested.
> Let me get up to date.
>
>
>
>
> On Thursday, January 19, 2017 11:08 AM, Vans S <[hidden email]> wrote:
> Actually I jumped the gun here:
>
>
> using a state_timeout as next event which is a valid
> event_type() as said in the docs produces:
>
> ** Reason for termination = error:{bad_action_from_state_function,
> {next_event,state_timeout,hi}}
> So state_timeout cant be used here.
>
> timeout,  cast, info can be used.
>
> {call, pid()} also cant be used.
>

That is a bug!

I missed to add a clause in event_type/1 for state_timeout when I
introduced it.  The missing clause for {call,From} has always not
been there - amazing nobody noticed!

I guess generating events of type 'internal' is the really useful
feature - the other types are mostly of theoretical value.
Using them will most probably be confusing.

I will try to squeeze in to fix that for 19.3.

>
>
>
> On Thursday, January 19, 2017 11:01 AM, Vans S <[hidden email]> wrote:
> > So if you in a state callback insert more next_event messages these are
> > inserted first in the queue, and a state_timeout 0 message is inserted last
> > in the queue.
>
> This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
> Also is there a priority such as external, internal, timeout, state_timeout, etc?

There is no priority between types.  First to enqueue is first to dequeue,
except for {next_event,_,_} actions that will be _before_ first to dequeue.

>
> Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
> regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
> is called.

Precisely.  All {next_event,_,_} actions in an event handler return will
be the first to dequeue for the next event handler, and the order between
them is that the first in the event handler action list will be the first
to dequeue.

So when the bug above has been fixed an action {next_event,state_timeout,_}
will produce an event that would be dequeued before the event from an action
{state_timeout,0,_}, with possible already enqueued events in between.

Furthermore multiple {next_event,state_timeout,_} actions will produce
one event each, but multiple {state_timeout,0,_} actions will override
each other so the last one wins hence only produce one event.

>
>
>
>
>
> On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
> On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:
>
> >
> > > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> > >
> > >
> > >
> > > This wording is really confusing:
> > >
> > >> instead the the time-out event is enqueued to ensure
> > >> that it gets processed before any not yet received
> > >> external event
> > > Because when I tried a test case
> > >
> > > init() ->
> > >  send(self(), hi),
> > >  {_,_,_,0}.  %0 timeout basically
> > >
> > > The 0 timeout procced before the 'hi' message.
> > > Using 1 as the timeout, 'hi' message procs first.
> > >
> > > But it says not yet received external event.  To me send() seems like
> > > an external event. Hence confusing.
> > Well, it was sent, but not yet received by the gen_statem’s main loop.
>
> Perfectly correct.
>
> While gen_statem processes enqueued events it is guaranteed to not enter a
> receive statement, so no new messages are received until after ther
> state_timeout 0 message.
>
> Other enqueued messages that are being processed such as next_event
> messages will be processed before a state_timeout 0 message.
>
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Vans S
> There is no priority between types.  First to enqueue is first to dequeue,
> except for {next_event,_,_} actions that will be _before_ first to dequeue.
This is logical and simple to reason about. Nice.

> So when the bug above has been fixed an action {next_event,state_timeout,_}
> will produce an event that would be dequeued before the event from an action
> {state_timeout,0,_}, with possible already enqueued events in between.

> Furthermore multiple {next_event,state_timeout,_} actions will produce
> one event each, but multiple {state_timeout,0,_} actions will override
> each other so the last one wins hence only produce one event.

Got it. One of my projects is itching to have state_timeout.

Right now I am working with gen_statem to handle netsplits and I think there
maybe a need to have a way for the gen_statem to not process any call/cast/info
until it gets to a certain state.  Take for example we have a need to implement
pairs trading for stocks. Using states such as:

step0_join_distribution
step1_subscribe_to_ticker1
step2_subscribe_to_ticker2
step3_process_messages

Our tree looks like:

nodedown -> {next_state, step0_join_distribution, {state_timeout, 10000, _}}
step0_join_distribution
  - monitor_nodes_for_nodedown

step1_subscribe_to_ticker1
  - udp:subscribe
  - if subscribed -> monitor_for_sub_loss, step2_subscribe_to_ticker2
  - else {state_timeout, 1000, _}

step2_subscribe_to_ticker2
  - udp:subscribe
  - if subscribed -> monitor_for_sub_loss, step3_process_messages
  - else {state_timeout, 1000, _}
step3_process_messages
  - Now we can process messages normally that come from
  - other parts of the distribution.


The issue I am grappling with now is if we fail on the subscription to the 3rd party API
(subscription via udp or tcp) we need to try again.  Trying again we use state_timeout
but this opens a gap for messages to be processed.  A possible approach would be to have a
catch_all handler for cast/call/info for all states that =/= step3_process_messages, it can
offload the mailbox to state for later processing or reply with a certain error like
not_ready_for_msgs.

But yea just some thoughts on use cases.



On Friday, January 20, 2017 3:03 AM, Raimo Niskanen <[hidden email]> wrote:
On Thu, Jan 19, 2017 at 04:35:19PM +0000, Vans S wrote:

> Okay same problem with R19.2.1
>
>
>
> On Thursday, January 19, 2017 11:15 AM, Vans S <[hidden email]> wrote:
> Yea ignore that. That is because I was not up to R19.2 when I tested.
> Let me get up to date.
>
>
>
>
> On Thursday, January 19, 2017 11:08 AM, Vans S <[hidden email]> wrote:
> Actually I jumped the gun here:
>
>
> using a state_timeout as next event which is a valid
> event_type() as said in the docs produces:
>
> ** Reason for termination = error:{bad_action_from_state_function,
> {next_event,state_timeout,hi}}
> So state_timeout cant be used here.
>
> timeout,  cast, info can be used.
>
> {call, pid()} also cant be used.
>

That is a bug!

I missed to add a clause in event_type/1 for state_timeout when I
introduced it.  The missing clause for {call,From} has always not
been there - amazing nobody noticed!
So when the bug above has been fixed an action {next_event,state_timeout,_}
will produce an event that would be dequeued before the event from an action
{state_timeout,0,_}, with possible already enqueued events in between.

Furthermore multiple {next_event,state_timeout,_} actions will produce
one event each, but multiple {state_timeout,0,_} actions will override
each other so the last one wins hence only produce one event.

I guess generating events of type 'internal' is the really useful
feature - the other types are mostly of theoretical value.
Using them will most probably be confusing.

I will try to squeeze in to fix that for 19.3.

>
>
>
> On Thursday, January 19, 2017 11:01 AM, Vans S <[hidden email]> wrote:
> > So if you in a state callback insert more next_event messages these are
> > inserted first in the queue, and a state_timeout 0 message is inserted last
> > in the queue.
>
> This clarifies things nicely.  Also what if one was to use {next_event, state_timeout .. vs {state_timeout ..
> Also is there a priority such as external, internal, timeout, state_timeout, etc?

There is no priority between types.  First to enqueue is first to dequeue,
except for {next_event,_,_} actions that will be _before_ first to dequeue.

>
> Or anything with next_event goes first into the queue (or top of stack if using {next_event, external .. ?)
> regardless queue or stack the idea is the same, it will be first to dequeue/pop. And this will happen before receive
> is called.

Precisely.  All {next_event,_,_} actions in an event handler return will
be the first to dequeue for the next event handler, and the order between
them is that the first in the event handler action list will be the first
to dequeue.

So when the bug above has been fixed an action {next_event,state_timeout,_}
will produce an event that would be dequeued before the event from an action
{state_timeout,0,_}, with possible already enqueued events in between.

Furthermore multiple {next_event,state_timeout,_} actions will produce
one event each, but multiple {state_timeout,0,_} actions will override
each other so the last one wins hence only produce one event.


>
>
>
>
>
> On Thursday, January 19, 2017 5:14 AM, Raimo Niskanen <[hidden email]> wrote:
> On Thu, Jan 19, 2017 at 11:59:37AM +0300, Alex S. wrote:
>
> >
> > > 19 янв. 2017 г., в 6:01, Vans S <[hidden email]> написал(а):
> > >
> > >
> > >
> > > This wording is really confusing:
> > >
> > >> instead the the time-out event is enqueued to ensure
> > >> that it gets processed before any not yet received
> > >> external event
> > > Because when I tried a test case
> > >
> > > init() ->
> > >  send(self(), hi),
> > >  {_,_,_,0}.  %0 timeout basically
> > >
> > > The 0 timeout procced before the 'hi' message.
> > > Using 1 as the timeout, 'hi' message procs first.
> > >
> > > But it says not yet received external event.  To me send() seems like
> > > an external event. Hence confusing.
> > Well, it was sent, but not yet received by the gen_statem’s main loop.
>
> Perfectly correct.
>
> While gen_statem processes enqueued events it is guaranteed to not enter a
> receive statement, so no new messages are received until after ther
> state_timeout 0 message.
>
> Other enqueued messages that are being processed such as next_event
> messages will be processed before a state_timeout 0 message.
>
> So if you in a state callback insert more next_event messages these are
> inserted first in the queue, and a state_timeout 0 message is inserted last
> in the queue.

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-question
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: gen_statem confusion

Fred Hebert-2
On 01/20, Vans S wrote:
>
>The issue I am grappling with now is if we fail on the subscription to the 3rd party API
>(subscription via udp or tcp) we need to try again.  Trying again we use state_timeout
>but this opens a gap for messages to be processed.  A possible approach would be to have a
>catch_all handler for cast/call/info for all states that =/= step3_process_messages, it can
>offload the mailbox to state for later processing or reply with a certain error like
>not_ready_for_msgs.
>

You may only need to use `postpone` functionality, which will re-enqueue
the message until a state change.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Loading...