Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Akka FSM Goto within future

Tags:

scala

akka

fsm

I'm trying to change FSM state in future but i doesn't work.. I think i'm looking for pipeTo like method.

When(State.Waiting) {
   case Event(anyMsg, anyData) =>
      asyncCode.map(res =>
         if (res == 1) {
            goto(State.Working) using Data.MyData
         } else {
            stay() replying "bad response"
         }

      )
}

goto command gets executed but fsm doesn't change state to State.Working

I found this work around by myself

When(State.Waiting) {
   case Event(anyMsg, anyData) =>
      asyncCode.map(res =>
         if (res == 1) {
            self ! "do job"
         } else {
            stay() replying "bad response"
         }

      )
   case Event("do job", anyData) => {
      goto(State.Working) using Data.MyData
   }
}

May be there is a better idea to solve problem

like image 340
Alexander Kondaurov Avatar asked Apr 07 '15 10:04

Alexander Kondaurov


2 Answers

Do not change the state of your actor in the future or anything not inside the main "thread". The correct way to solve your problem is to send a message to self which will just change the state, like

When(State.Waiting) {
  case Event(anyMsg, anyData) =>
    asyncCode.map(res =>
      if (res == 1) {
        self ! GoToWorking(Data.MyData)
      } else {
        self ! Stay
      }
    )
    goto(State.WaitingForResponse)
}

When (State.WaitingForResponse) {
  case Event(GoToWorking(data), _) =>
    goto(State.Working) using data
  case Event(Stay,_) =>
    stay()
}
like image 58
M4ks Avatar answered Nov 13 '22 07:11

M4ks


You should never close over and modify the state of an actor from an asynchronous callback (for example Future combinators). This is also true for FSM methods, they are private to the actor. The only way an actor should react to asynchronous events is by receiving a message. Your second code is almost correct except that you should not even call stay() from the callback. The asynchronous result should end up as a message sent to the actor, which in turn can change its state. You might want to introduce a new waiting state which you transition to when launching the asynch call, and once it is finished (the actor receives the result), go to State.Working.

like image 36
Endre Varga Avatar answered Nov 13 '22 08:11

Endre Varga