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
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()
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With