0
votes

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?

1

1 Answers

2
votes

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.