向Akka Typed中的父参与者发送消息

mzaanser  于 2022-11-06  发布在  其他
关注(0)|答案(2)|浏览(138)

标题是不言自明的,我希望能够发送一个消息给一个父参与者(意思是我想要父的ActorRef)。在Akka Classic(无类型)中,父参与者的ActorRef可以通过以下方式从子参与者的ActorContext中获得:

context.parent

(see例如,X1E0F1X)。
然而,Akka Typed中的akka.actor.typed.scaladsl.ActorContext并没有为父角色公开一个ActorRef。Scala中是否有一种惯用的方法来为父角色获取一个ActorRef

wvyml7n5

wvyml7n51#

TLDR:在创建子角色时将父角色引用注入子角色。
Akka Typed强制执行严格的协议,因此您需要绝对清楚地表明“此参与者与另一个参与者对话”。公认的答案是一种解决方法(转换为经典并使用父对象),但也有其缺点:现在您不再强制类型。
下面是一些代码,你可以从这些代码入手,看看所有类型是如何被强制执行的。你可以用不同的方式来建模这些特性,但你应该明白其中的含义:

object ParentActor {
  sealed trait Command 

  case class DoSomething() extends Command

  // you do not have to do this, but creating another trait
  // allows you to narrow the amount of messages the parent can receive from the child
  sealed trait ChildNotification extends Command
  case class MessageFromChild() extends ChildNotification

  def apply(): Behavior[Command] = {
    Behaviors.receive( (context, message) => 
      message match {
        case DoSomething() =>
          // create a child that knows about its parent
          context.spawn(ChildActor(context.self), "child")
          Behaviors.same

        case MessageFromChild() =>
          context.log.info("I received a message from my child")
          Behaviors.same
      })
  }
}

object ChildActor {
  sealed trait Command
  case class Work() extends Command

  // inject the parent here (or any other actor that matches the signature)
  def apply(parent: ActorRef[ParentActor.ChildNotification]): Behavior[Command] = {
     Behaviors.receive( (context, message) => 
       message match {
         case Work() =>
           // send message to parent actor (or any other actor with that type)
           parent ! ParentActor.MessageFromChild()
           Behaviors.same

     })
  }
}

顺便说一句,我使用的是akka类型的“函数”语法,但你也可以使用更“面向对象”的语法,它遵循同样的方法。

bq9c1y66

bq9c1y662#

如果你在类型化的Akka中,唯一能包含ActorRef的[Scala]类型是ActorRef[Nothing],它是一个不能发送消息的ActorRef,所以它的实用性有限。
至少在经典API存在的时候是这样:

import akka.actor.typed.scaladsl.adapter._

type ClassicActorRef = akka.actor.ActorRef

val parentActorRef = context.toClassic.parent

这将是一个非类型化的ActorRef,也就是说,您可以自由地发送父参与者永远不会接受的消息。
如果你想要一个对参与者父代的类型化引用,你需要在派生子参与者时嵌入它,就像你想要一个对当前消息发送者的类型化引用,你需要在你的协议中嵌入replyTo
context.sender在键入的ActorContext中不存在,原因与context.parent不存在的原因相同;用于复制经典X1 M8 N1 X的解决方法是类似的:(一个月九个月)

相关问题