FSM Usage pattern

111 views
Skip to first unread message

Edmondo Porcu

unread,
May 24, 2012, 8:12:38 AM5/24/12
to <Senza nome>
Dear all,

I have an Actor which might be in two states.Idle or Processing.When
in Idle, if a message is received,it directly moves to Processing,
where it starts a long procedure. At the end

At the end of the procedure, the actor should
- Go back to Idle if no message is received during the Processing
- Start a new processing if one or more messages have been received
during the Processing phase.

I thought to implement through a FSM[State, Boolean] but my problem is
how to handle the transaction at the end of the Processing phase.

In fact, let's say we enter the Processing phase because of 3 messages
received, at the end of the processing, how can I know in which state
should I go?


Best Regards
Edmondo

Edmondo Porcu

unread,
May 24, 2012, 9:17:34 AM5/24/12
to <Senza nome>
I tried to implement this like the following:

class RecomputationActor(codeBlock: =>Unit) extends Actor with
FSM[ActorState,Boolean] {
startWith(Idle,false)

when(Idle){
case Event(event,_) =>goto(Processing) using(false)
}

when(Processing){
case Event(event,_) => stay using(true)
}

onTransition{
case Idle->Processing => codeBlock; goto(Idle)
case Processing->Idle => if(nextStateData)
goto(Processing) using false
}


initialize

}

However when I test it, nothing happens:

class RecomputationActorTest extends Spec {
val system = ActorSystem("MySystem")
describe("A recomputation actor "){

it("must change state correctly"){

val actor = system.actorOf(Props(new RecomputationActor( {

println("hello")

Thread.sleep(100)
} )
with LoggingFSM[ActorState,Boolean] ))
actor ! "Compute"
actor ! "Compute"
actor ! "Compute"
actor ! "Compute"
}

}

}
Where am I wrong?




2012/5/24 Edmondo Porcu <edmond...@gmail.com>:

√iktor Ҡlang

unread,
May 24, 2012, 9:21:44 AM5/24/12
to akka...@googlegroups.com
I think you should go to Idle as the response to a receive timeout.

Cheers,


--
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To post to this group, send email to akka...@googlegroups.com.
To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.




--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Edmondo Porcu

unread,
May 24, 2012, 9:28:23 AM5/24/12
to akka...@googlegroups.com
Is there a way to test an FMS in a multi-thread environment so that
the actor is not executed in the calling dispatcher?

Best
Edmondo

2012/5/24 √iktor Ҡlang <viktor...@gmail.com>:

Edmondo Porcu

unread,
May 24, 2012, 9:28:59 AM5/24/12
to akka...@googlegroups.com
And also could you please clarify your comment I didn't really understand...

2012/5/24 Edmondo Porcu <edmond...@gmail.com>:

√iktor Ҡlang

unread,
May 24, 2012, 9:30:05 AM5/24/12
to akka...@googlegroups.com
On Thu, May 24, 2012 at 3:28 PM, Edmondo Porcu <edmond...@gmail.com> wrote:
And also could you please clarify your comment I didn't really understand...


√iktor Ҡlang

unread,
May 24, 2012, 9:30:22 AM5/24/12
to akka...@googlegroups.com
On Thu, May 24, 2012 at 3:28 PM, Edmondo Porcu <edmond...@gmail.com> wrote:
Is there a way to test an FMS in a multi-thread environment so that
the actor is not executed in the calling dispatcher?

What does that mean?

Edmondo Porcu

unread,
May 24, 2012, 9:35:47 AM5/24/12
to akka...@googlegroups.com
Well I would like to test that with many threads sending messages at
once, while the actor is still busy in processing, the states are
correctly managed .

I still don't understand your comment about the timeout:

when(Idle){
case Event(event,_) =>goto(Processing) using(false)
}

when(Processing){
case Event(event,_) => stay using(true)
}

onTransition{
case Idle->Processing => codeBlock; goto(Idle)
case Processing->Idle => if(nextStateData)
goto(Processing) using false
}

When idle and entering into processing: I process and go back to idle.
When going back to idle, if the new state will be true (to recompute )
I go again to Processing.

Is that forbidden or wrong?

Best


2012/5/24 √iktor Ҡlang <viktor...@gmail.com>:

Roland Kuhn

unread,
May 24, 2012, 9:37:51 AM5/24/12
to akka...@googlegroups.com
Hi Edmondo,

24 maj 2012 kl. 15:17 skrev Edmondo Porcu:

> I tried to implement this like the following:
>
> class RecomputationActor(codeBlock: =>Unit) extends Actor with
> FSM[ActorState,Boolean] {
> startWith(Idle,false)
>
> when(Idle){
> case Event(event,_) =>goto(Processing) using(false)
> }
>
> when(Processing){
> case Event(event,_) => stay using(true)
> }
>
> onTransition{
> case Idle->Processing => codeBlock; goto(Idle)

onTransition takes a PartialFunction[(S, S), Unit], meaning that it does not return anything and can only do side-effects. In particular it cannot effect state transitions. The current design of FSM is deliberately limited to executing exactly one behavior per message, allowing a maximum of one transition per message. Everything else would be prone to infinite loops.

In short: when done processing a message, you must know which state shall be the next one (which is always true no matter how you phrase it), and that state must be returned from the when() block.

Regards,

Roland
> --
> You received this message because you are subscribed to the Google Groups "Akka User List" group.
> To post to this group, send email to akka...@googlegroups.com.
> To unsubscribe from this group, send email to akka-user+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/akka-user?hl=en.
>

Roland Kuhn
Typesafe – The software stack for applications that scale.
twitter: @rolandkuhn


√iktor Ҡlang

unread,
May 24, 2012, 9:43:39 AM5/24/12
to akka...@googlegroups.com
On Thu, May 24, 2012 at 3:35 PM, Edmondo Porcu <edmond...@gmail.com> wrote:
Well I would like to test that with many threads sending messages at
once, while the actor is still busy in processing, the states are
correctly managed .

I still don't understand your comment about the timeout:

Did you read the entire FSM docs? If not, do. Then ask.

Edmondo Porcu

unread,
May 24, 2012, 9:43:48 AM5/24/12
to akka...@googlegroups.com
Thanks,
that was what I was missing :).

However the onTransition is allowed to send a message to the actor
itself, right?

Best

2012/5/24 Roland Kuhn <goo...@rkuhn.info>:

√iktor Ҡlang

unread,
May 24, 2012, 9:56:41 AM5/24/12
to akka...@googlegroups.com
You're still not using a receive timeout as I suggest, but anyway...

Cheers,


On Thu, May 24, 2012 at 3:52 PM, Edmondo Porcu <edmond...@gmail.com> wrote:
I did but the fact that I didn't know one could not force transitions
in the onTransition change everything... the right code seems this one
then:


class RecomputationActor(codeBlock: =>Unit) extends Actor with
LoggingFSM[ActorState,Boolean] {
 startWith(Waiting,false)

 when(Waiting){
   case Event(RecomputationEvent,_) =>goto(Processing) using(false)

 }

 when(Processing){
     case Event(RecomputationEvent,_) => stay using(true)
     case Event(RecomputationFinished,_) => goto(Waiting)

 }

 onTransition{
               case Waiting->Processing => codeBlock; self !
RecomputationFinished
               case Processing->Waiting => if(nextStateData) self !
RecomputationEvent
   }


  initialize

}

Is this legal?

Edmondo Porcu

unread,
May 24, 2012, 9:52:34 AM5/24/12
to akka...@googlegroups.com
I did but the fact that I didn't know one could not force transitions
in the onTransition change everything... the right code seems this one
then:

class RecomputationActor(codeBlock: =>Unit) extends Actor with
LoggingFSM[ActorState,Boolean] {
startWith(Waiting,false)

when(Waiting){
case Event(RecomputationEvent,_) =>goto(Processing) using(false)

}

when(Processing){
case Event(RecomputationEvent,_) => stay using(true)
case Event(RecomputationFinished,_) => goto(Waiting)

}

onTransition{
case Waiting->Processing => codeBlock; self !
RecomputationFinished
case Processing->Waiting => if(nextStateData) self !
RecomputationEvent
}


initialize

}

Is this legal?

Edmondo Porcu

unread,
May 24, 2012, 10:05:57 AM5/24/12
to akka...@googlegroups.com
Ahahah thank you for your excellent support. I might try to explain
my use case in two lines because maybe there is a better
implementation:

- When the actor receives an event, it starts a certain function
(fixed). If during this function any other events are received, the
computation should be executed again (meaning that the previous result
is already old. If not the actor can go into a sleeping state.

Is there a better implementation? I don't see where a timeout could fit here...

Best


2012/5/24 Roland Kuhn <goo...@rkuhn.info>:
> Hi Edmondo,
>
> 24 maj 2012 kl. 15:52 skrev Edmondo Porcu:
>
>> I did but the fact that I didn't know one could not force transitions
>> in the onTransition change everything... the right code seems this one
>> then:
>>
>> class RecomputationActor(codeBlock: =>Unit) extends Actor with
>> LoggingFSM[ActorState,Boolean] {
>>  startWith(Waiting,false)
>>
>>  when(Waiting){
>>    case Event(RecomputationEvent,_) =>goto(Processing) using(false)
>>
>>  }
>>
>>  when(Processing){
>>      case Event(RecomputationEvent,_) => stay using(true)
>>      case Event(RecomputationFinished,_) => goto(Waiting)
>>
>>  }
>>
>>  onTransition{
>>                case Waiting->Processing => codeBlock; self !
>> RecomputationFinished
>>                case Processing->Waiting => if(nextStateData) self !
>> RecomputationEvent
>>    }
>>
>>
>>   initialize
>>
>> }
>>
>> Is this legal?
>>
> I won’t sue you for it ;-) And I think it should do what you want; quite creative use of onTransition, I’d think!
>
> Regards,
>
> Roland
> Roland Kuhn
> Typesafe – The software stack for applications that scale.
> twitter: @rolandkuhn

Roland Kuhn

unread,
May 24, 2012, 10:13:56 AM5/24/12
to akka...@googlegroups.com
Your solution is a good one, the only potential for improvement would require that the computation would be partitionable, so that you only ever do a small step and abort if other messages intervene, but that would be much more complex, not only for handling the continuation state of the computation itself, you would also need to have some kind of abort policy which ensures that once in a while it succeeds even if things would like to intervene.

The state timeout comment from Viktor was before you showed your intention more clearly with the last solution, you don’t need it here.

Regards,

Roland

Roland Kuhn

unread,
May 24, 2012, 10:00:32 AM5/24/12
to akka...@googlegroups.com
Hi Edmondo,

24 maj 2012 kl. 15:52 skrev Edmondo Porcu:

> I did but the fact that I didn't know one could not force transitions
> in the onTransition change everything... the right code seems this one
> then:
>
> class RecomputationActor(codeBlock: =>Unit) extends Actor with
> LoggingFSM[ActorState,Boolean] {
> startWith(Waiting,false)
>
> when(Waiting){
> case Event(RecomputationEvent,_) =>goto(Processing) using(false)
>
> }
>
> when(Processing){
> case Event(RecomputationEvent,_) => stay using(true)
> case Event(RecomputationFinished,_) => goto(Waiting)
>
> }
>
> onTransition{
> case Waiting->Processing => codeBlock; self !
> RecomputationFinished
> case Processing->Waiting => if(nextStateData) self !
> RecomputationEvent
> }
>
>
> initialize
>
> }
>
> Is this legal?
>
I won’t sue you for it ;-) And I think it should do what you want; quite creative use of onTransition, I’d think!

Regards,

Roland

Roland Kuhn
Typesafe – The software stack for applications that scale.
twitter: @rolandkuhn


Reply all
Reply to author
Forward
0 new messages