簡體   English   中英

Akka.Net 發布和訂閱領域事件

[英]Akka.Net Publishing and Subscribing Domain Events

我開始用新兵訓練營研究 Akka.Net 框架。

我可以使用事件溯源來理解基本的 Actor 概念和持久性。

我一直在理解領域事件將如何被其他參與者調度和接收。

限制為單個系統本地部署的 Actors 和無 DI 容器,並使用 c#/ASP.NET API,我將每個 AgreegateRoot 分離到它自己的項目中

我正在構思類似的東西

  • 經理演員

    • -聚合根
      • --兒童演員1
      • --兒童演員2
      • --ChildActor n
    • -ValidationActor

Manager Actor 將接收命令消息並通過驗證過程,如果驗證通過,將發送到 AggregateRoot Actor。 事件將在根或子 Actor 內生成。

請就以下事項提出建議:

要從實體內部發布類似於 eventbus的事件,我可以使用以下語法嗎?

Context.System.EventStream.Publish(MyEvent);

要訂閱一個事件,我明白語法是

System.EventStream.Subscribe( subscriber,MyEvent)

我希望Actor發布的事件由Handlers(其他Actors)處理,其中當前的AggregateRoot Actor或里面的子實體應該不知道。

這是我完全卡住的地方。 這是如何實現的?

System.EventStream.Subscribe 中的訂閱者是 IActorRef。 為了得到這個,我需要了解課程。

我應該創建一個啟動引導程序來引用所有項目/ AggregateRoots 並在那里構建訂閱到消息類型嗎?

我試圖找到博客或文章,但運氣不佳。

提前致謝。

我將每個 AgreegateRoot 分成自己的項目

我不會為每個 AggregateRoot 建立一個單獨的項目,這對我來說似乎有點矯枉過正。 你能從中得到什么? 你可以只使用一個類/演員,不需要一個完全獨立的項目。

聽起來您可能對如何引用表示您的事件的 C# 類型感到困惑,如果您為每個 AggregateRoot 有一個單獨的項目,這並不奇怪 - 您很快就會遇到循環引用。 嘗試從單個項目開始,在該項目中使用文件夾分隔有界上下文。 在每個文件夾中,創建您需要的任何聚合,以及它們負責的任何事件。 這樣,所有參與者都可以看到所有事件類型。 一旦這種情況增長/變得無法管理,您可以考慮將其拆分為單獨的項目,大致如下:

  • MyApp.BoundedContext1
  • MyApp.BoundedContext1.Events
  • MyApp.BoundedContext2
  • MyApp.BoundedContext2.Events

請注意,您的參與者生成和訂閱的事件代表了整個系統中的一種公共合同/API。 將它們作為上述單獨的 DLL 可避免循環引用(因為 .Events 項目不引用任何內容)。 所以在這個結構中, MyApp.BoundedContext1可以引用MyApp.BoundedContext1.Events並發布它們。 MyApp.BoundedContext2也可以引用MyApp.BoundedContext1.Events並訂閱它們。

我希望Actor發布的事件由Handlers(其他Actors)處理,其中當前的AggregateRoot Actor或里面的子實體應該不知道。

這是我完全卡住的地方。 這是如何實現的?

您的發布者不需要訂閱者的知識。 發布者只是向 EventStream 發布一條消息。 定義actor 和事件類型的上下文應該是相同的(即發布者應該“擁有”他們的事件類型)。 例如,如果您有一個發布ThingValidated事件的ValidationActor ,則它們應該位於相同的上下文中。

System.EventStream.Subscribe 中的訂閱者是 IActorRef。 為了得到這個,我需要了解課程。

哪一堂課? 訂戶已經了解自己。 您可以使用Self來獲取IActorRef 如果您指的是事件類,請參閱上面有關如何構建項目以引用它的信息。

一旦創建了一個actor,它就可以注冊它感興趣的任何事件類型——如果需要,您可以將此代碼放在actor本身的初始化代碼中,或者如果您有單例樣式的actor,在某種引導程序函數中若你寧可。

另一個解決方案是使用Akka.Cluster.Sharding ,它非常適合這個用例。 然而; 我承認集群分片不是初學者的話題。 集群分片允許您設置如何通過道具創建您的演員以及將消息映射到特定“實體”的策略。

這是我在上面鏈接的博客文章中的示例中為演員設置的集群分片設置的示例:

using(var system = ActorSystem.Create("cluster-system"))
{
    var sharding = ClusterSharding.Get(system);
    var shardRegion = sharding.Start(
        typeName: nameof(MyActor), 
        entityProps: Props.Create<MyActor>(), // the Props used to create entities
        settings: ClusterShardingSettings.Create(system),
        messageExtractor: new MessageExtractor(maxNumberOfNodes * 10)
    );

    // ... etc
}

然后你可以像這樣發送消息:

region.Tell(new ShardEnvelope("<entity-id>", new MyMessage()));

消息提取器

上面提到的消息提取器是使這一切正常工作的關鍵組件。 消息提取器允許您將消息映射到特定實體(實際上是 entityId)。 因此,例如,如果您的消息都包含目標實體的 Id,那么這將變得簡單。 這是一個示例消息提取器(再次來自 petabridge 博客文章和 Akka.Net 代碼庫):

public sealed class MessageExtractor : HashCodeMessageExtractor
{
    public MessageExtractor(int maxNumberOfShards) : base(maxNumberOfShards) { }
    public override string EntityId(object message) => 
        (message as ShardEnvelope)?.EntityId;
    public override object EntityMessage(object message) => 
        (message as ShardEnvelope)?.Payload;
}

public sealed class ShardEnvelope
{
    public readonly string EntityId;
    public readonly object Payload;

    public ShardEnvelope(string entityId, object payload)
    {
        EntityId = entityId;
        Payload = payload;
    }
}

我承認這似乎有點矯枉過正,我認為如果 Akka.Net 中對虛擬演員有更好的一流支持,這將得到糾正。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM