在处理一个相当大的Akka应用程序时,我遇到了一个非常简单的结构,涉及普通方法和非Akka类的工作,但是在使用Akka时却很难掌握,因此我来这里问一下您建议解决这个问题的最佳方法是什么。问题是这样的,我有一个父级actor,让我们称之为"Connector",Connector具有描述其在接收ConnectCommand实例时应执行的行为。首先,它使用HttpClient提交表单,然后转到几个URL以检查某些会话参数,并最终向接收者(称为"Consumer")发送连接消息,其中包含它需要使用API的所有内容。现在,我非常喜欢告诉别人,而不是拉/请求,所以在我看来,实现这一点是一个艰巨的任务。让我们来看看。由HttpClientActor返回的所有响应都是Response实例,所以首先想到的是在我的actor中定义多个行为,并在完成连接过程的某个步骤后逐步更改行为到下一步。
这种方法的优点是使用tell而不是ask,但主要缺点是代码变得非常难以阅读。
现在我觉得这个Actor需要一些改变,但在我看来有两个选择。
第一个选择涉及将每个HttpRequest和Response拆分为单独的Actor,并在Connector actor中聚合结果。这样做的好处是非常易读,使用tell,而且不应该影响性能,因为Akka是建立在处理大量Actor的基础之上的。唯一的缺点是我需要为这些状态的部分创建许多容器类,这些状态需要从Stage5Actor传递到Connector actor。这会导致内存开销很大(如果我错了,请纠正我)。
第二种方法是使用Ask模式将步骤连接在一起。这将导致一个单独的Connector actor,由于Spray对其Http Client也是如此,我认为这可能是一个有效的解决方案。唯一的缺点是,因为所有东西都基于外部的Http API,超时可能成为一个问题。如果Akka团队推荐这种方法,那么如何处理完全不可预测的所有超时呢?
请注意,这个实现需要能够使用监督策略,因为我们整个当前的方法都是基于它构建的。
如果您认为有比我提到的更好的解决方案,请告诉我!我目前非常喜欢Akka,每一条建议都是对我的经验和知识的增益,不仅对我个人,也对整个社区有益 :D。此外,我认为这是更多人偶尔会遇到的问题。
提前感谢您,也要感谢Akka团队开发出如此棒的库!
PS. 这个问题最初是在Akka GitHub上提出的,但我决定在这里发布,因为这既是一个Actor模型相关的问题,也是一个Akka相关的问题。
GitHub上的问题链接:https://github.com/akka/akka/issues/16080
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,但主要缺点是代码变得非常难以阅读。
现在我觉得这个Actor需要一些改变,但在我看来有两个选择。
第一个选择涉及将每个HttpRequest和Response拆分为单独的Actor,并在Connector actor中聚合结果。这样做的好处是非常易读,使用tell,而且不应该影响性能,因为Akka是建立在处理大量Actor的基础之上的。唯一的缺点是我需要为这些状态的部分创建许多容器类,这些状态需要从Stage5Actor传递到Connector actor。这会导致内存开销很大(如果我错了,请纠正我)。
第二种方法是使用Ask模式将步骤连接在一起。这将导致一个单独的Connector actor,由于Spray对其Http Client也是如此,我认为这可能是一个有效的解决方案。唯一的缺点是,因为所有东西都基于外部的Http API,超时可能成为一个问题。如果Akka团队推荐这种方法,那么如何处理完全不可预测的所有超时呢?
请注意,这个实现需要能够使用监督策略,因为我们整个当前的方法都是基于它构建的。
如果您认为有比我提到的更好的解决方案,请告诉我!我目前非常喜欢Akka,每一条建议都是对我的经验和知识的增益,不仅对我个人,也对整个社区有益 :D。此外,我认为这是更多人偶尔会遇到的问题。
提前感谢您,也要感谢Akka团队开发出如此棒的库!
PS. 这个问题最初是在Akka GitHub上提出的,但我决定在这里发布,因为这既是一个Actor模型相关的问题,也是一个Akka相关的问题。
GitHub上的问题链接:https://github.com/akka/akka/issues/16080