Alexander Kondaurov
Alexander Kondaurov

Reputation: 4133

Akka FSM Goto within future

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

Upvotes: 5

Views: 1701

Answers (2)

M4ks
M4ks

Reputation: 12024

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()
}

Upvotes: 10

Endre Varga
Endre Varga

Reputation: 1863

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.

Upvotes: 5

Related Questions