通过AKKA中的worker actors检索state actors

4

我有三个演员来处理CQRS情景。其中ProductWorkerActor负责命令部分,ProductQueryWorkerActor负责查询部分,ProductStateActor负责状态部分。

我处理查询的方式是使用:

ProductQueryWorkerActor.Ask<ProductState>("give-me-product-state-for-product-1000")

来自ProductQueryWorkerActor的代码:

if (message == "give-me-product-state-for-product-1000")
{
    var actor = Context.ActorSelection("akka://catalogSystem/user/productState/1000");
    var psDTO = actor.Ask<ProductStateDTO>(message).Result;
    Sender.Tell(ps);
}

请忽略访问产品状态使用的路径。它是硬编码的,是为了使代码读起来更简单。
1.像我在这种情况下所使用的那样,我应该使用"Ask"来检索产品状态吗?"Ask"被称为"Future"吗?
2.我应该把状态暴露给外部工作而不是Actor本身作为DTO吗?
3.要更改产品的任何状态,我应该在"ProductWorkerActor"中处理消息处理还是在"ProductStateActor"本身中处理?在第二种情况下,"ProductWorkerActor"向"ProductStateWorker"发送一条消息,"ProductStateWorker"处理消息,更改状态并向"ProductWorkerActor"发送另一条消息,表示已通过验证并更改了状态。
1个回答

4
如果您正在使用事件溯源与您的actor一起使用,我建议您使用Akka.Persistence。它处理读/写actor分离,并将减轻你的负担。
如果没有,我认为你的设计的基本问题是,虽然你有独立的actor用于读/写状态,但状态本身只由一个actor处理。为什么?CQRS的一个要点是有单独的模型来优化它们的角色(读或写)。
例如:您可以有一个处理器actor(例如ProductActor),根据传入的命令更改其状态,以及一堆不同的只读actor(例如ProductHistoryActor、ProductListActor),每个都有自己的状态,针对它们的角色进行了优化。只读actor可以订阅事件流以侦听有关处理器actor状态更改的传入消息,并相应地更新自己的状态,而处理器actor在处理完命令后会使用actor系统的事件流发布有关状态更改的消息。
补充1:在我看来,使用Ask来在actor之间通信是一种反模式。在您的示例中,您正在使用查询actor将消息通过到状态actor,然后阻止当前actor直到响应到达(这对性能非常不利),只是为了将消息发送回发件人。与其使用:
var psDTO = actor.Ask<ProductStateDTO>(message).Result;
Sender.Tell(ps);

您可以简单地写成以下内容:
actor.Forward(message);

actor直接向发送方发送响应(您查询的actor无需参与发送响应)。

广告2:这取决于您的情况,但请记住——永远不要将可变对象作为消息传递,特别是在发送后再使用它们。

广告3:我认为在您的示例中,ProductWorkerActorProductStateWorker之间的区别是人为的。从您展示的内容来看,它们应该是一个单一的实体。


关于第1点和第2点的回答非常出色。我从Jamie Allen的《Essential AKKA》一书中获得了将Worker Actor和State Actor分离的灵感。他建议将状态和行为分开。 - wonderful world
'actor.Forward'不起作用,因为actor是ActorSelection。ActorSelection没有Forward扩展。我不确定如何从ActorSelection中获取基础actor,以便可以进行Forward操作。 - wonderful world
Forward基本上相当于Tell(message, Sender)。在处理Actor选择时要小心 - 如果不是真正必要的话,就不应该使用它们。这方面有一些讲座 - Bartosz Sypytkowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接