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 叫 Futures 吗?

  2. 我应该将状态作为 DTO 暴露给外部工作而不是演员本身吗?

  3. 要更改产品的任何状态,我应该在ProductWorkerActor中还是在ProductStateActor本身中处理消息?在第二种情况下,ProductWorkerActor向ProductStateWorker发送一条消息,ProductStateWorker处理该消息,更改状态并向ProductWorkerActor发送另一条消息,它通过验证并更改了状态。

4

1 回答 1

4

如果您对演员使用事件溯源,我建议您使用Akka.Persistence. 它处理读/写演员分离,并会从你的肩膀上承担很多负担。

If not, in my opinion basic problem with your design is that, while you have separate actors for reading/writing to state, state itself is handled in only one actor. Why? One of the points of CQRS is to have a separate models optimized for serving their role (either read or write).

In example: you can have one handler actor (eg. ProductActor) changing it's state based on incoming commands, and bunch of different readonly actors (eg. ProductHistoryActor, ProductListActor), each with it's own state optimized for their role. Readonly actors may subscribe to event stream to listen for incoming messages about handler actor's state changes and updating their own states accordingly, while handler actor after handling a command publishes message about state change using actor system's event stream.

Ad. 1: In my opinion using Ask to communicate between actors is an anti-pattern. In your example, you're using query actor to pass message through to state actor, then blocking current actor until response arrives (which is very bad for performance) just to send message back to sender. Instead of using:

var psDTO = actor.Ask<ProductStateDTO>(message).Result;
Sender.Tell(ps);

you could simply write:

actor.Forward(message);

and let actor send response directly to sender (you query actor doesn't need to participate with sending the response).

Ad. 2: It depends on your case, but remember - you should never pass mutable objects as messages, especially when you use them after sending.

Ad. 3: I think that in your example distinction between ProductWorkerActor and ProductStateWorker is artificial. From what you're showing, they should be a single entity IMO.

于 2015-05-19T19:03:51.553 回答