我可以 Read/Write 来自具有相同 PersistenceId 的不同参与者吗?

Can I Read/Write from separate actors with same PersistenceId?

Petabridge blog's Akka.Persistence intro 明确表示不能有多个 actors 具有相同的 PersistenceId:

The PersistenceId field is important - it uniquely identifies an entity that is persisting its state using Akka.Persistence, and there should be exactly one persistent actor at any given time for a single PersistenceId.

[...] so imagine if you have two actors with the same PersistenceId but different sequence numbers writing to the same store. It will be chaos and will inevitably error out - so that’s why it’s crucial that every PersistenceId be globally unique within your ActorSystem (at least for all actors writing to that store.)

我可以想到这样一种场景,您将有两个独立的参与者:一个负责将持久性状态保存到数据库(即调用 Persist()),另一个在手动重播日志中的消息要求这样做(即调用 Recover())。读取和写入操作将发生在不同的参与者身上。只有一个曾经写过,也只有一个曾经读过。但是,两者都需要相同的 PersistenceId。

我相信在这种情况下,让两个参与者使用相同的 PersistenceId 应该是安全的。但是鉴于上面引用的上述警告,是否有任何理由说明这种方法在实践中可能是危险的?

I can think of a scenario where you would have two separate actors: one that takes care of saving persistence state to database (i.e. calls Persist()), and another one that replays messages from the journal when manually requested to do so (i.e. calls Recover()). The read and write operations would occur from different actors. Only one ever writes, and only one ever reads. However, both need the same PersistenceId.

您需要的行为已公开为 Persistent Actors and Persistent Views。来自文档:

While a persistent actor may be used to produce and persist events, views are used only to read internal state based on them. Like the persistent actor, a view has a PersistenceId to specify a collection of events to be resent to current view. This value should however be correlated with the PersistentId of an actor who is the producer of the events.

编辑:已更新以提供有关如何在持久视图中访问事件的更多信息。

您可以通过覆盖 Persistent ViewReceive 方法从日志加载。此方法的参数是一个对象,因此您需要将该对象转换为您通过 Persistent Actor.

持久化的任何事件。

Receive 方法还处理您传递给视图的任何其他消息 - 例如来自表示层的读取请求。我通常在视图内部存储一个事件列表,return 一个自定义视图模型。

protected override bool Receive(object message)
{
    // if the message is a previously persisted event, update our internal list
    var e = message as MyEvent;
    if (e != null) _events.Add(e);
    return true;

    // if the message is a request for a view model, read from our list of stored events
    var r = message as ReadRequest;
    if (r == null) return false;
    Sender.Tell(new ViewModel(_events));
    return true;
}