需要帮助了解Akka Typed ask的返回类型

tjvv9vkg  于 2022-11-23  发布在  其他
关注(0)|答案(1)|浏览(154)

我正在尝试让“ask”为Akka Typed工作。我在网上看了一些例子,我认为我基本上复制了它们所显示的内容,但是当我试图评估“ask”的响应时,我得到了一个编译器错误。下面是我的最小可重复示例。
SuperSimpleAsker是一个从MyWidgetKeeper参与者请求“小部件”的参与者。响应是一个表示小部件id的字符串。到目前为止,我所尝试做的就是将接收到的小部件id记录为“Success”消息,并在以后添加更多与该id有关的内容。当创建SuperSimpleAsker时,MyWidgetKeeper的ActorRef被传入。我省略了创建参与者的Main程序以保持代码简单。
我得到的错误是:

type mismatch;
 found   : Unit
 required: widgets.SuperSimpleAsker.Request

此错误出现在两个logger.* 行上(在代码列表末尾的Case Failure和Case Success块内)。
我不明白代码的哪一部分需要一个“widgetts.SuperSimpleAsker.Request”对象,也不明白为什么。

package widgets

import scala.concurrent.duration.DurationInt
import scala.util.{Failure, Success}
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior}
import akka.util.Timeout
import com.typesafe.scalalogging.LazyLogging

object MyWidgetKeeper {
  sealed trait Request
  case class GetWidget(replyTo: ActorRef[Response]) extends Request

  sealed trait Response
  case class WidgetResponse(widget: String) extends Response

  def apply(): Behavior[Request] =
    new MyWidgetKeeper().myWidgetKeeper()

}

class MyWidgetKeeper {
  import MyWidgetKeeper._
  def myWidgetKeeper(): Behavior[Request] = {
    Behaviors.receive { (context, message) =>
      message match {
        case GetWidget(replyTo) =>
          replyTo ! WidgetResponse("12345")
          Behaviors.same
      }
    }
  }
}

object SuperSimpleAsker {
  sealed trait Request
  case object DoStuff extends Request

  def apply(widgetKeeper: ActorRef[MyWidgetKeeper.Request]): Behavior[Request] =
    new SuperSimpleAsker(widgetKeeper).simpleAsker()
}

class SuperSimpleAsker(widgetKeeper: ActorRef[MyWidgetKeeper.Request]) extends LazyLogging{
  import SuperSimpleAsker._
  import widgets.MyWidgetKeeper.GetWidget
  
  private def simpleAsker(): Behavior[Request] = {
    Behaviors.receive { (context, message) =>
      message match {
        case DoStuff =>
          logger.info(f"Doing stuff")
          implicit val timeout = Timeout(2000 millis)
          context.ask(widgetKeeper, GetWidget)
          {
            case Failure(exception) =>
              logger.error(f"Failed: ${exception.getMessage}")
            case Success(response: MyWidgetKeeper.Response) =>
              response match {
                case MyWidgetKeeper.WidgetResponse(id) =>
                  logger.info(f"Success: Got Widget# $id")
                  // Do some more stuff with the widget id
              }
          }
          Behaviors.same
      }
    }
  }
}
shyt4zoc

shyt4zoc1#

在Akka Typed的context.ask中,传递的函数将成功或失败的ask转换为一条消息,发送给参与者,理想情况下不会产生副作用。
因此,您的SuperSimpleAsker将不得不添加消息,以使请求可以转换为:

object SuperSimpleAsker {
  sealed trait Request
  case object DoStuff extends Request

  case class WidgetResponseFor(widgetId: String) extends Request
  case object NoWidgetResponse extends Request

  def apply(widgetKeeper: ActorRef[MyWidgetKeeper.Request]): Behavior[Request] =
    new SuperSimpleAsker(widgetKeeper).simpleAsker()
}

class SuperSimpleAsker(widgetKeeper: ActorRef[MyWidgetKeeper.Request]) extends LazyLogging{
  import SuperSimpleAsker._
  import widgets.MyWidgetKeeper.GetWidget
  
  private def simpleAsker(): Behavior[Request] = {
    Behaviors.receive { (context, message) =>
      message match {
        case DoStuff =>
          logger.info(f"Doing stuff")
          implicit val timeout = Timeout(2000 millis)
          context.ask(widgetKeeper, GetWidget)
          {
            case Failure(_) => // there's actually only one possible exception: timed out
              NoWidgetResponse
            case Success(response: MyWidgetKeeper.Response) =>
              WidgetResponseFor(response.widget)
          }
          Behaviors.same

        case WidgetResponseFor(id) =>
          logger.info(f"Success: Got Widget# $id")
          // Do stuff with the widget id

          Behaviors.same

        case NoWidgetResponse =>
          logger.error("Failed")
          Behaviors.same
      }
    }
  }
}

相关问题