对有类型的 Actor 提出请求失败,而不是用 Try 换行

Fail Ask Request on Typed Actor instead wrap with Try

示例

 import akka.actor.typed.scaladsl.AskPattern._
      object MyActor {
        sealed trait Command
        case class MyCommand(replyTo: ActorRef[Try[String]]) extends Command

        def apply(): Behaviors.Receive[Command] = {
          val failureMessage = util.Failure(new RuntimeException("Timeout"))
          Behaviors.receiveMessage {
            case MyCommand(replyTo) => replyTo ! failureMessage
              Behaviors.same
          }
        }
      }

      val worker = testKit.spawn(MyActor())

      // Act
      val res = worker.ask[Try[String]](me => MyActor.MyCommand(replyTo = me))

      // Assert
      println(Await.result(res, Duration.Inf)) // Return Failure(java.lang.RuntimeException: Timeout)
      // But i want to do:
      intercept[RuntimeException] {
        Await.result(res, Duration.Inf)
      }
      // and on success i want to return instead of Success[T] as T
    }

请注意,我用 Try 包装结果以便 return SuccessFailure。问题是我不想这样做,我想在 ask 请求中使整个 Future 失败。

可以吗?

对于询问响应是成功响应还是失败响应,在 Akka Typed 中,最好使用 askWithStatus 并调整协议以使用 StatusReply:

import akka.pattern.StatusReply

object MyActor {
  sealed trait Command
  case class MyCommand(replyTo: ActorRef[StatusReply[String]]) extends Command

  // can also wrap a Throwable, but it's generally advised to wrap a string
  val failure = StatusReply.Error("Timeout")

  def apply(): Behavior[Command] =
    Behaviors.receiveMessage {
      case MyCommand(replyTo) =>
        replyTo ! failure
        Behaviors.same
    }
}

然后,执行询问:

val res: Future[String] = worker.askWithStatus[String](MyActor.MyCommand(_))

res 将:

  • 如果被问到的演员回答 StatusReply.Success(string)
  • ,则用 string 完成
  • 如果被询问的演员回答 StatusReply.Error(errorString)
  • ,则失败 StatusReply.ErrorMessage(errorString)
  • 如果被询问的演员回答 StatusReply.Error(x: Throwable)
  • ,则失败 x
  • 失败,通常的异常是正常的 ask 如果在收到响应之前达到超时,则会失败

至于为什么建议包装一个字符串错误消息,这是因为通常情况下,请求 actor 做某事的代码不应该对 actor 的任何部分的内部结构有足够的了解异常消息和(可能)异常类型之外的异常是有意义的。如果您不愿意将该细节(例如堆栈跟踪)暴露给网络或 API 消费者,您可能不应该在您的询问响应中暴露它。如果您在餐厅点餐,而厨房里的厨师将装有您食物的平底锅掉在地上,您是否需要服务员(您 API 到厨房)回来告诉您“厨师将您的食物掉在了地上”地板上的食物”,或者只是让服务员或经理过来说“抱歉,您的订单会延迟,这里有一杯饮料(或礼券或其他)”?