当我在一个相当大的Akka应用程序上工作时,我遇到了一个非常简单的结构,当使用普通的方法和非Akka类时,但是当使用Akka时,这实际上是很难解决的,这就是为什么我来到这里,问你建议什么是解决这个问题的最好方法。
问题是这样的,我有一个父参与者,让我们称他为“连接器”,连接器有一个行为描述当它接收到一个ConnectCommand示例时它应该做什么。首先,它使用HttpClient提交一个表单,然后它转到几个URL来检查一些会话参数,最后向发送者(称为“消费者”)发送一个连接消息,其中包含它使用API所需的一切。
现在,我非常喜欢tell,而不是pull / ask,所以在我看来,实现这是一个很难的任务。让我们来回顾一下。HttpClientActor返回的所有响应都是一个Response示例,所以首先想到的是在我的actor中定义多个行为,并在连接过程的某个步骤完成后,逐渐地将行为更改为下一步。
private final PartialFunction<Object, BoxedUnit> inital = ReceiveBuilder
.match(ConnectCommand.class, c -> this.startConnection())
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage1 = ReceiveBuilder
.match(Response.class, this::stage1)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage2 = ReceiveBuilder
.match(Response.class, this::stage2)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage3 = ReceiveBuilder
.match(Response.class, this::stage3)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage4 = ReceiveBuilder
.match(Response.class, this::stage4)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage5 = ReceiveBuilder
.match(Response.class, this::stage5)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage6 = ReceiveBuilder
.match(Response.class, this::stage6)
.matchAny(this::unhandled)
.build();
private final PartialFunction<Object, BoxedUnit> stage7 = ReceiveBuilder
.match(Response.class, this::stage7)
.matchAny(this::unhandled)
.build();
这样做的优点是使用tell,而不是ask,但主要的缺点是代码变得非常不可读。
现在我在这一点上,我觉得这个演员需要一些改变,在一个好的方式,但有两个选择,在我看来。
第一种方法涉及将每个HttpRequest和Response拆分为一个单独的Actor,并将结果聚合到Connector Actor中,使用tell,不应该影响性能,因为Akka是为处理大量演员而构建的。这样做的唯一缺点是,我需要为这些需要从Stage 5Actor传递到连接器参与者。这导致了大量的内存开销(如果我错了,请纠正我)。
第二种方法是使用Ask模式将步骤连接在一起。这将产生一个连接器参与者,因为Spray也为它的Http客户端这样做,我认为这可能是一个有效的解决方案。唯一的缺点是,因为所有东西都依赖于外部Http API,超时可能会成为一个问题。如果Akka团队推荐这种方法,如何处理所有完全不可预测的超时?
请注意,此实现需要能够使用监督策略,因为我们当前的整个方法都是基于此。
如果你觉得有比我提到的更好的解决方案,请告诉我!我真的很喜欢Akka a.t.m.,我得到的每一条建议,都是经验和知识的收获,不仅对我,而且对整个社区:D.另外,我认为这是一个越来越多的人偶尔遇到的问题。
提前感谢,也非常感谢Akka团队制作了如此令人敬畏的lib!
这个问题是第一次问Akka GitHub本身,但我决定张贴在这里,因为这是一个演员模型相关的问题,因为一个Akka相关的问题。
链接到GitHub上的问题:https://github.com/akka/akka/issues/16080
1条答案
按热度按时间xurqigkl1#
在我看来,你不一定需要N个阶段来收集响应,如果你知道你在等待多少个响应,你就可以在一个行为下收集所有的响应。
此外,在使用
ask
的任何场景中,都可以轻松地将其替换为一个中间Actor来保存此上下文,并通过tell
传递所有消息。(好吧,对于整个请求,您应该仍然有一个超时时间),并且您可以将所有未完成的阶段捆绑到一个Actor中,而不是为每个ask
额外添加一个Actor。Jamie艾伦很好地描述了这个场景,如Effective Akka中的Extra and Cameo Patterns。
因此,考虑到这一切,你也许可以遵循以下思路:
sender
使用者。tell
启动后续请求。此时,您可以让Cameo或连接器作为监督者,这样您的监督策略仍然可以按您的意愿工作。Receive
区块中的Cameo可以等待来自Connections的回应。这不一定是ask
上的await
。只要接受receive
中的消息,然后更新您的内部状态即可。tell
响应原始Consumer。