Akka FSM Goto within future
Asked Answered
S

2

5

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

Skiest answered 7/4, 2015 at 10:39 Comment(0)
T
10

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()
}
Tenney answered 7/4, 2015 at 11:10 Comment(3)
But stay() would keep the state of WaitingForResponse, right?Pons
Yes. When you use FSM in Akka you must "return" action you perform - even if it's a "no-on".Tenney
or using pipe pattern val f = asyncCode.map(res => if(res=1){ GoToWorking(Data.MyData) }else{ Stay }) ; f pipeTo self; goto(State.WaitingFOrResponse)Apache
M
5

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.

Murky answered 7/4, 2015 at 11:4 Comment(2)
The below comment by M4ks explains the same in detail.Murky
Yes, it did but with exampleSkiest

© 2022 - 2024 — McMap. All rights reserved.