Akka Pattern - 演员树,回复原始来源

时间:2013-10-10 16:31:15

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

这是一个设计问题;

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

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

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

问题是管理从最终/叶子演员传回给客户演员的响应(msgX&amp; /或msgY)的最佳模式是什么?

我可以想到以下选项;

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

仅供参考我正在使用Akka 2.2.1。

干杯!

3 个答案:

答案 0 :(得分:21)

您可以使用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!
}

在这种情况下,邮件的“发件人”字段永远不会更改,因此ActorC将回复原始的Client_Actor!

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

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

答案 1 :(得分:1)

最简单的方法是将带有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(); }

答案 2 :(得分:1)

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

代码有点太大,不能包含在这里,也不是开源的。

为了使其正常工作,通过系统传播的消息必须带有ActorRef s,指示响应消息将发送给谁(我很少设计只回复sender的演员)。

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

无论如何,通过这些功能,您可以设置非常灵活的路由拓扑。