Scala Akka Typed - 使用 ask 在行为内部发送请求

问题描述

我对 akka 输入有点陌生,我试图发送需要在给定时间内得到答复的消息。
我发现带有 ask 的请求-响应模式看起来很有趣,但有没有办法在已经定义的 BehavIoUrs.receive 中实现它?

这里的想法是在每次玩家回答或超时后调用 nextPlayerTurn

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

在这种情况下,在发送 YourTurnMsg 后,玩家应该以停止计时器的 GuessMsg 进行响应,这不会发生,因为在 refereeTurn BegavIoUr 中执行案例匹配而不是 Success(它总是在超时)。

我是否对询问模式有错误的想法,应该使用计时器创建一个新的行为?

解决方法

如果您想使用 ask 模式,那么处理结果的代码需要向主要参与者发送消息,而不是尝试直接进行任何处理。您可以根据结果发送不同的消息,或者只发送原始结果并在 Actor 中处理它,但您不能在该代码中执行任何依赖于 Actor 状态的操作,因为它可以在不同的线程上运行。

但是 ask 并不便宜,因此在这种情况下,最好设置一个计时器并查看哪个消息先返回。