Akka设计校长

在使用相当大的Akka应用程序时,我在使用普通方法和非Akka类时遇到了一个非常简单的结构,但在使用Akka时实际上很难确定,这就是为什么我来这里问你推荐什么是解决这个问题的最佳方法。

所以问题是这个,我有一个父actor,让我们称他为“Connector”,Connector有行为描述它在收到ConnectCommand实例时应该做什么。 首先,它使用HttpClient提交表单,然后转到几个URL以检查某些会话参数,并最终向Sender(称为“Consumer”)发送包含使用API​​所需的所有内容的连接消息。

现在,我是一个忠实的粉丝,而不是拉/问,所以实现这一点在我看来是一项艰巨的任务。 我们来看看吧。 HttpClientActor返回的所有响应都是一个Response实例,因此首先想到的是在我的actor中定义了多个行为,并且在连接过程的某个步骤完成后,逐步地将行为更改为下一步。

private final PartialFunction inital = ReceiveBuilder .match(ConnectCommand.class, c -> this.startConnection()) .matchAny(this::unhandled) .build(); private final PartialFunction stage1 = ReceiveBuilder .match(Response.class, this::stage1) .matchAny(this::unhandled) .build(); private final PartialFunction stage2 = ReceiveBuilder .match(Response.class, this::stage2) .matchAny(this::unhandled) .build(); private final PartialFunction stage3 = ReceiveBuilder .match(Response.class, this::stage3) .matchAny(this::unhandled) .build(); private final PartialFunction stage4 = ReceiveBuilder .match(Response.class, this::stage4) .matchAny(this::unhandled) .build(); private final PartialFunction stage5 = ReceiveBuilder .match(Response.class, this::stage5) .matchAny(this::unhandled) .build(); private final PartialFunction stage6 = ReceiveBuilder .match(Response.class, this::stage6) .matchAny(this::unhandled) .build(); private final PartialFunction stage7 = ReceiveBuilder .match(Response.class, this::stage7) .matchAny(this::unhandled) .build(); 

这样做的好处是它使用tell而不是ask,但主要缺点是代码变得非常难以理解。

现在,我觉得这个演员需要一个很好的方式进行一些改变,但我认为有两种选择。

第一个涉及将每个HttpRequest和Response拆分为一个单独的Actor并在Connector actor中聚合结果。 这样做的优点是非常易读,使用tell并且不应该损害性能,因为Akka是为处理大量演员而构建的。 唯一的缺点是我需要为需要从Stage5Actor传递给Connector actor的状态部分创建许多容器类。 这会产生很大的内存开销(如果我错了,请纠正我)。

第二种方法是使用Ask模式将步骤连接在一起。 这将导致一个连接器actor,因为Spray也为它的Http Client做了这样的事情,我认为它可能是一个有效的解决方案。 唯一的缺点是,因为一切都在外部Http API之上,超时可能会成为一个问题。 如果Akka团队推荐这种方法,那么如何处理完全不可预测的所有超时。

请注意,此实施需要能够使用监督策略,因为我们目前的整个方法都是基于此。

如果您觉得有比我提到的更好的解决方案,请告诉我们! 我真的很喜欢Akka atm,我得到的每一条建议,都是经验和知识的获得,不仅对我而言,对整个社区来说:D。 此外,我认为这是一个问题,每隔一段时间就会遇到更多的人。

在此先感谢Akka团队制作这样一款非常棒的lib!

PS。 这个问题首先在Akka github本身上被问到,但我决定在这里发布,因为这与作为Akka相关问题的Actor模型相关问题一样多。

链接到github上的问题: https : //github.com/akka/akka/issues/16080

在我看来,你不一定需要N个阶段来收集回复。 如果你知道你在等待多少回复,你可以在一个行为下收集它们。

此外,在您使用ask任何场景中,您都可以轻松地将其替换为中间Actor来保存此上下文并通过tell传递所有消息。 这实际上就是ask问题,但主要区别在于你不必为每个问题指定超时(好吧,你应该还有一个超时的整体请求)并且你可以将所有未完成的阶段捆绑在一个每个问题的演员而不是额外的演员。

杰米艾伦非常好地描述了这种情景作为有效阿卡的额外和浮雕模式 。

因此,考虑到这一切,您可以遵循以下方面的内容:

  • 当Consumer将消息发送到Connector时,Connector可以为此请求上下文创建一个新的Actor(Cameo)。 您必须捕获此Actor中的sender使用者。
  • Cameo演员可以通过tell的后续请求。 此时,您可以将Cameo或Connector作为主管,这样您的监督策略仍可按您的需要运行。
  • 其中的Cameo Receive块可以等待来自Connections的响应。 这不一定是在await问题。 只需接受接收中的消息,然后更新您的内部状态。
  • 完成所有连接后,您可以通过tell回复原始消费者。