【问题标题】:Akka Pattern - Actor tree, reply to original sourceAkka Pattern - Actor 树,回复原文
【发布时间】:2013-10-18 13:00:16
【问题描述】:

这是一个设计问题;

假设我有一棵执行大量处理的演员树。处理由客户端/连接参与者启动(即树是服务器)。最终,客户端参与者想要一个响应。 IE。我有一个看起来像这样的演员系统。

    ActorA  <---reqData--- Client_Actor
       | msgA                    /|\                      
      \|/                         |                 
    ActorB                        |                  
  msgB |  \ msgD                  | 
      \|/  \/                     | 
    ActorC  ActorD---------msgY-->|
       |_____________msgX_________|

客户端系统想要的响应是叶参与者的输出(即ActorC 和/或ActorD)。树中的这些参与者可能正在与外部系统交互。这棵树可能是一组预定义的可能路由的actors(即Client_actor 只是有一个actorref 指向actor 树的根,ActorA)。

问题是管理将响应(msgX 和/或 msgY)从 final/leaf actor 发送回客户端 actor 的最佳模式是什么?

我能想到以下选项;

  • 为每个连接客户端创建一个树并让参与者跟踪发送者,当他们获得msgXmsgY 时,将其发送回原始发送者参考,以便消息通过树。即每个演员将保留原始发件人的参考。
  • 以某种方式在reqData 消息中发送Client_Actor 引用并将其复制到树中使用的所有消息,以便叶参与者可以直接回复Client_actor... 这似乎是性能最高的选项。不知道如何做到这一点(我正在以某种方式在包含客户端actor ref 的消息案例类上考虑一个特征)...
  • 不知何故,根据通过树传递的消息中的唯一 ID 查找客户端 Actor,或使用 Actorselection(不确定这与远程处理的效果如何)...
  • 更好的东西...

仅供参考,我使用的是 Akka 2.2.1。

干杯!

【问题讨论】:

  • 应该将 msgX 和 msgY 都传递给客户端 Actor,还是发送一条消息应该取消发送另一条消息?
  • 客户端actor可能期望msgXmsyY或两者兼有msgX &amp; msgY,具体取决于reqData消息中捕获的状态。为简单起见,假设客户端 Actor 知道它想要什么(即为此效果创建期货)并且 ActorB 将有条件地向叶子 Actor 发送消息。

标签: scala design-patterns akka message-passing akka-cluster


【解决方案1】:

您可以使用forward 方法将消息从原始发件人转发给每个级别的子发件人。

在 Client_Actor 中:

actorA ! "hello"

在 ActorA 中:

def receive = {
  case msg =>
    ???
    actorB forward msg
}

在 ActorB 中:

def receive = {
  case msg =>
    ???
    actorC forward msg
}

在 ActorC 中:

def receive = {
  case msg =>
    ???
    sender ! "reply" // sender is Client_Actor!
}

在这种情况下,消息的'sender'字段永远不会改变,所以ActorC会回复原来的Client_Actor!

您可以使用tell 方法变体进一步扩展此功能,该变体可让您指定发件人:

destinationActor.tell("my message", someSenderActor);

【讨论】:

    【解决方案2】:

    最简单的方法是将带有 ref 的消息发送到源 Client_Actor

    Client
     sendMsg(Client to, Client resultTo)
    
    Client_Actor
     req_data(Client to){
       sendMsg(to, this);
     }
    

    这是一个不错的选择,如果您不知道哪个客户有原始海报的结果,哪个没有。

    如果您知道这一点并且 Client_Actor 只是一个(就像我们有一棵树并且只有 LEAFS 将始终响应且只有 Client_Actor),您可以执行以下操作:

    Client
      register_actor(Client actor){this.actor = actor;}
      call_actor(){ this.actor.sendMsg(); }
    

    【讨论】:

    • 这是一种很好的方法,为此我的问题是如何轻松表示此信息-最好使用应用于消息reqData,msgA,msgB &amp; msgD 的特征吗?这在 Scala 中应该如何实现?
    【解决方案3】:

    对于这样的情况,我写了一个叫做ResponseAggregator的东西。它是一个Actor,根据需要实例化(而不是作为持久的单个实例),将目标ActorRef、任意key(如果单个目标由多个聚合器提供,则用于区分聚合器)作为参数,一个完成谓词,它接受一个 Seq[Any] 持有到目前为止聚合器收到的响应,如果这些响应表示聚合过程的完成和一个超时值,则返回 true。聚合器接受并收集传入消息,直到谓词返回 true 或超时到期。一旦聚合完成(包括由于超时),所有接收到的消息都会连同一个指示聚合是否超时的标志一起发送到目的地。

    代码有点太大,这里不包含,而且不是开源的。

    为此,通过系统传播的消息必须带有ActorRefs,表明将向谁发送响应消息(我很少设计只回复sender的参与者)。

    我经常将消息值的replyTo 字段定义为ActorRef*,然后使用我的MulticastActor 类,它启用!*“发送到多个收件人”运算符。这在消息构造中具有语法简洁的优点(与使用 Option[ActorRef] 或 Seq[ActorRef] 相比)并且具有相同的开销(需要构造一些东西来捕获对actor ref 或 refs 的回复)。

    不管怎样,有了这些东西,你可以设置非常灵活的路由拓扑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 2016-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      相关资源
      最近更新 更多