Scala Akka Typed - send request inside behavior with ask - scala

I'm kinda new to akka typed and I was trying to send a message which requires an answer within a given time.
I found the request-response pattern with ask which seemed interesting but is there a way to implement it inside of an already defined Behaviours.receive?
Here the idea is to call nextPlayerTurn each time a player answers or after a timeout
override def refereeTurn(): Behavior[Msg] = Behaviors.receive {
case (_, msg: GuessMsg) =>
if(currentPlayer.isDefined && currentPlayer.get == msg.getSender) {
controller ! msg
} else {
println("Player tried to guess after Timeout")
}
Behaviors.same
case (context, msg: ReceivedResponseMsg) =>
if(currentPlayer.isDefined && currentPlayer.get == msg.getSender)
nextPlayerTurn(context)
Behaviors.same
...
}
...
/**
* Tells to a player to start his turn and sets a timer that defines time in which a player has to make a guess.
* If such guess isn't made, sends that user an end turn message, fails the promise of his turn and allows next
* player to play his turn
*/
override def nextPlayerTurn(ctx: ActorContext[Msg]): Unit = {
implicit val timeout: Timeout = Timeout.timeout
currentPlayer = Option(turnManager.nextPlayer)
ctx.ask[Msg,Msg](currentPlayer.get, ref => YourTurnMsg(ref)) {
case Success(msg: GuessMsg) => println("\n SUCCESS"); msg
case Failure(_) => println(currentPlayer.get +" didn't guess in time"); TurnEnd(currentPlayer.get)
case _ => TurnEnd(currentPlayer.get)
}
}
In this case after the YourTurnMsg is sent the player is supposed to respond with a GuessMsg which stops the timer, this never happens due to the case matching inside refereeTurn Begaviour being executed instead of the Success (which instead always gives a Failure after the Timeout).
Did i get the wrong idea about the ask patter and should just make a new Behaviour with a timer?

If you want to use the ask pattern then the code that handles the result needs to send a message to the main actor rather than trying to do any processing directly. You can send a different message based on the result or just send the raw result and process it in the actor, but you must not do anything that depends on actor state in that code because it could be run on a different thread.
But ask is not cheap so in this case it seems better to just set a timer and see which message comes back first.

Related

Why does the Identify message find an actor in an actor selection after its termination?

Within a test-program, I want to check that an Actor (child) remains terminated and is not created again after some computation. My test looks like (it is part of a TestKit subclass):
val childSelection = system.actorSelection(parent.path / "*")
childSelection ! Identify(0)
val child = expectMsgPF {
case ActorIdentity(0, Some(ref)) => ref
}
watch(child)
// some computation that should end in stopping child
expectTermiated(child)
// some computation that should not create a new child
childSelection ! Identify(1)
expectMsg(ActorIdentity(1, None))
The last line sometimes unexpectedly fails, stating that the message ActorIdentity(1, Some(parent.path/child-name)) was received instead of the expected one. This means that, even after receiving the Terminated message (resulting from the expectTerminated(...) test), sending the Identify message to an actor selection does not necessarily result in the ActorIdentity(..., None) response.
Does anybody know what the akka framework actually does and how it works in this case? Thanks in advance for your help!
Meanwhile, I replaced the last line of my test with:
val identities = receiveWhile() {
case ActorIdentity(1, Some(ref)) => ref == child
}
if (identities.isEmpty) {
expectMsg(ActorIdentity(1, None))
} else {
expectNoMsg
}
which seems to work fine but is quite more complex to read (and write)...
Since you selection is on parent.path / "*", your parent actor probably have another child that is responding to the Identity message. Check what identity your receive after stopping the child, to figure out what other child is responding.

Some of the Actor messages are missing --AKKA FSM

Here is the sample code flow:
class FSMActor{
when(Idle) {
case Event(Start, Uninitialized) =>
case Event(InitMap(inMap), t # EvaluteRuleMap(v, c)) =>
logger.info(s"State = $stateName, Event = Event(_, InitMap(inMap))")
goto(EVALRule) using t.copy(ruleMap = inMap)
}
when(EVALRule) {
case Event(RowMap(m), t # EvaluteRuleMap(v, c)) =>
logger.debug("input row map m " + m)
**if ( <somecondition> ) { // If comment this if-else block, I could see rowMaps being received.
logger.debug(s"Moving to State Trigger x=$x")
goto(TriggerRule) using t.copy(ruleMap = x.get)
} else {
logger.debug(s"staying in EVALRule, x = $x")
stay
}**
}
when(TriggerRule) {
case Event(_, _) => ....
}
}
}
When the control in in "EVALRule" state, It will keep receiving streams maps(RowMap) and based on some computation, it moves to trigger rule.
Unfortunately for some weird reason, some of the incoming RowMaps are not being received at "case Event(RowMap(m), t # EvaluteRuleMap(v, c)) =>" and
If I comment the code bock (bolded in the above code) then I could see all incoming rowmaps being received.
Could anyone let me know why is so? I've been trying to find the cause but couldn't get it to.
Appreciate your help, thanks.
When if ( <somecondition> ) is true, you are moving to the TriggerRule state. In that state you are looking for messages of type EVENT instead of Event (all caps). So the message is not handled by the FSM.
In general, when missing messages in FSM, the best way to debug is to write a whenUnhandled block with a log/print statement to see what messages are not handled by the states you have defined.
There was some issue with message handling in the code itself, we debugged it and fixed the issue, now its working seamlessly.

Omitting all Scala Actor messages except the last

I want omit all the same type of messages except the last one:
def receive = {
case Message(type:MessageType, data:Int) =>
// remove previous and get only last message of passed MessageType
}
for example when I send:
actor ! Message(MessageType.RUN, 1)
actor ! Message(MessageType.RUN, 2)
actor ! Message(MessageType.FLY, 1)
then I want to recevie only:
Message(MessageType.RUN, 2)
Message(MessageType.FLY, 1)
Of course if they will be send very fast, or on high CPU load
You could wait a very short amount of time, storing the most recent messages that arrive, and then process only those most recent ones. This can be accomplished by sending messages to yourself, and scheduleOnce. See the second example under the Akka HowTo: Common Patterns, Scheduling Periodic Messages. Instead of scheduling ticks whenever the last tick ends, you can wait until new messages arrive. Here's an example of something like that:
case class ProcessThis(msg: Message)
case object ProcessNow
var onHold = Map.empty[MessageType, Message]
var timer: Option[Cancellable] = None
def receive = {
case msg # Message(t, _) =>
onHold += t -> msg
if (timer.isEmpty) {
import context.dispatcher
timer = Some(context.system.scheduler.scheduleOnce(1 millis, self, ProcessNow))
}
case ProcessNow =>
timer foreach { _.cancel() }
timer = None
for (m <- onHold.values) self ! ProcessThis(m)
onHold = Map.empty
case ProcessThis(Message(t, data)) =>
// really process the message
}
Incoming Messages are not actually processed right away, but are stored in a Map that keeps only the last of each MessageType. On the ProcessNow tick message, they are really processed.
You can change the length of time you wait (in my example set to 1 millisecond) to strike a balance between responsivity (length of time from a message arriving to response) and efficiency (CPU or other resources used or held up).
type is not a good name for a field, so let's use messageType instead. This code should do what you want:
var lastMessage: Option[Message] = None
def receive = {
case m => {
if (lastMessage.fold(false)(_.messageType != m.messageType)) {
// do something with lastMessage.get
}
lastMessage = Some(m)
}
}

How to implement a self-cancelling poller without using a var?

I'm curious if it's possible to safely implement a self-cancelling poller without using a var to keep the instance of akka.actor.Cancellable
So far, I came up with something like what you see in the example below. However, I'm curious if it's safe to assume that the "tick" message will never be dispatched before the hotswap happens, i.e the line that schedules the poller:
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
is basically the same as:
val poll = context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick")
tick(1, 5, poll)
So, I would think that in some cases the first tick would be received before the hotswap has a chance to happen... Thoughts?
import akka.actor.{Cancellable, ActorSystem}
import akka.actor.ActorDSL._
import concurrent.duration._
object PollerDemo {
def run() {
implicit val system = ActorSystem("DemoPoller")
import system.dispatcher
actor(new Act{
become {
case "tick" => println("UH-OH!")
case "start" =>
become {
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
}
}
def tick(curr:Long, max:Long, poll:Cancellable):Receive = {
case "tick" => {
println(s"poll $curr/$max")
if(curr > max)
cancel(poll)
else
become{ tick(curr + 1, max, poll) }
}
}
def cancel(poll:Cancellable) {
println("cancelling")
poll.cancel()
println(s"cancelled successfully? ${poll.isCancelled}")
println("shutting down")
context.system.shutdown()
}
}) ! "start"
system.awaitTermination(1 minute)
}
}
My guess is that your code will be okay. Remember, actors only process their mailbox one at a time. When you receive the start message, you setup a timer that will deliver another message to the mailbox and then you swap the receive implementation. Because you do the receive swap while you are still processing the start message, then you will have already changed the actors's receive behavior before it processes the next message in the mailbox. So when it moves on to process the tick message you can be sure that it will be using the new receive behavior.
You could verify this by sending an additional tick message inside the first become like so:
become {
self ! "tick"
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
}
Here we are really eliminating the timer from the equation when asking if a message sent during the become block will be processed by the old receive or the new receive. I did not run this, but from my understanding or akka, both of these ticks should be handled by the new receive.
You really can't do pure functional programming with actors. Sending them messages is a side-effect. Since their receive function doesn't return a result, all the actor can do when receiving a message is to side effect. Just about every single thing your code does is for side-effects
You might be avoiding vars in your implementation of the code, but become is mutating a var in the Actor superclass. context.system.scheduler.schedule is clearly side-effecting and mutating state somewhere. Every single thing that cancel does is a side effect. system.awaitTermination(1 minute) is not a function...

How can one verify messages sent to self are delivered when testing Akka actors?

I have an Actor that is similar to the following Actor in function.
case class SupervisingActor() extends Actor {
protected val processRouter = //round robin router to remote workers
override def receive = {
case StartProcessing => { //sent from main or someplace else
for (some specified number of process actions ){
processRouter ! WorkInstructions
}
}
case ProcessResults(resultDetails) => { //sent from the remote workers when they complete their work
//do something with the results
if(all of the results have been received){
//*********************
self ! EndProcess //This is the line in question
//*********************
}
}
case EndProcess {
//do some reporting
//shutdown the ActorSystem
}
}
}
}
How can I verify the EndProcess message is sent to self in tests?
I'm using scalatest 2.0.M4, Akka 2.0.3 and Scala 1.9.2.
An actor sending to itself is very much an intimiate detail of how that actor performs a certain function, hence I would rather test the effect of that message than whether or not that message has been delivered. I’d argue that sending to self is the same as having a private helper method on an object in classical OOP: you also do not test whether that one is invoked, you test whether the right thing happened in the end.
As a side note: you could implement your own message queue type (see https://doc.akka.io/docs/akka/snapshot/mailboxes.html#creating-your-own-mailbox-type) and have that allow the inspection or tracing of message sends. The beauty of this approach is that it can be inserted purely by configuration into the actor under test.
In the past, I have overridden the implementation for ! so that I could add debug/logging. Just call super.! when you're done, and be extra careful not to do anything that would throw an exception.
I had the same issue with an FSM actor. I tried setting up a custom mailbox as per the accepted answer but a few minutes didn't get it working. I also attempted to override the tell operator as per another answer but that was not possible as self is a final val. Eventually I just replaced:
self ! whatever
with:
sendToSelf(whatever)
and added that method into the actor as:
// test can override this
protected def sendToSelf(msg: Any) {
self ! msg
}
then in the test overrode the method to capture the self sent message and sent it back into the fsm to complete the work:
#transient var sent: Seq[Any] = Seq.empty
val fsm = TestFSMRef(new MyActor(x,yz) {
override def sendToSelf(msg: Any) {
sent = sent :+ msg
}
})
// yes this is clunky but it works
var wait = 100
while( sent.isEmpty && wait > 0 ){
Thread.sleep(10)
wait = wait - 10
}
fsm ! sent.head