我有三个角色来处理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);
}
请忽略用于访问产品状态的路径。它是硬编码的,有意使代码读取更简单。
我是否应该使用询问,因为我在这种情况下用来检索产品的状态? Ask是否称为期货?
我是否应该将状态作为DTO暴露给外部工作而不是演员本身?
要更改产品的任何状态,我应该在 ProductWorkerActor 或 ProductStateActor 本身处理消息处理吗?在第二种情况下, ProductWorkerActor 向 ProductStateWorker 发送消息, ProductStateWorker 处理消息,更改状态并向 ProductWorkerActor 它通过了验证并更改了状态。
答案 0 :(得分:4)
如果您与演员一起使用Event Sourcing,我建议您使用Akka.Persistence
。它处理读/写演员分离,并将承担你肩负的很多负担。
如果没有,在我看来,你的设计的基本问题是,虽然你有单独的演员来读/写状态,但状态本身只在一个演员中处理。为什么? CQRS的一个要点是为服务其角色(读取或写入)而优化的单独模型。
在示例中:您可以让一个处理程序actor(例如ProductActor
)根据传入的命令更改它的状态,以及一堆不同的只读参与者(例如{。{ {1}},ProductHistoryActor
),每个人都有自己的状态,为自己的角色进行了优化。只读参与者可以订阅事件流以监听关于处理程序参与者状态改变的传入消息并相应地更新它们自己的状态,而处理器参与者在处理命令之后使用参与者系统的事件流发布关于状态改变的消息。
广告。 1 :在我看来,使用ProductListActor
在演员之间进行交流是一种反模式。在您的示例中,您使用查询actor将消息传递给状态actor,然后阻止当前actor直到响应到达(这对性能非常不利),只是将消息发送回发送方。而不是使用:
Ask
你可以简单地写一下:
var psDTO = actor.Ask<ProductStateDTO>(message).Result;
Sender.Tell(ps);
让actor.Forward(message);
直接向发送方发送回复(您查询的参与者不需要参与发送回复)。
广告。 2 :这取决于你的情况,但请记住 - 你永远不应该将可变对象作为消息传递,特别是在发送后使用它们时。
广告。 3 :我认为在您的示例中,actor
和ProductWorkerActor
之间的区别是人为的。根据您的展示,他们应该是IMO的单一实体。