有没有一种方法可以获取Akka.NET中给定节点上当前可用的所有实例化actor

时间:2018-06-25 16:43:49

标签: c# akka.net akka.net-cluster akka.net-networking

我的应用程序中包含以下代码,该代码可在群集中创建Akka.NET actor的实例,例如:

_actorSystem = ActorSystem.Create("mycluster");
_actoraActor = this._actorSystem.ActorOf<ActorA>();

请注意,由于我打算创建ActorA类型的N个actor,并且不想管理名称,因此我故意省略了name属性。运行上面的代码,我得到一个演员,该演员的ID如下所示:

akka://mycluster/user/$a#1293118665

我遇到的问题是试图从另一个节点确定Actor路径。因此,例如,我尝试执行以下操作:

public class ActorB : ReceiveActor
{
    private readonly Cluster Cluster = Akka.Cluster.Cluster.Get(Context.System);


    public ActorB()
    {

        this.Receive<ActorIdentity>(this.IdentifyMessageReceived);
        this.ReceiveAsync<ClusterEvent.MemberUp>(this.MemberUpReceived);
    }

    protected override void PreStart()
    {
        this.Cluster.Subscribe(this.Self, ClusterEvent.InitialStateAsEvents, new[]
        {
            typeof(ClusterEvent.IMemberEvent),
            typeof(ClusterEvent.UnreachableMember)                
        });
    }

    protected override void PostStop()
    {
        this.Cluster.Unsubscribe(this.Self);
    }

    private async Task<bool> MemberUpReceived(ClusterEvent.MemberUp obj)
    {
        if (obj.Member.HasRole("actora"))
        {
            //!The problem is here.
            //ALL YOU ARE PROVIDED IS THE NODE ADDRESS:  
            //Obviously this makes sense because it's the node that has come alive
            //and not the instances themselves.

            string address = obj.Member.Address.ToString();
            //akka.tcp://mycluster@localhost:666
            Context.ActorSelection(address).Tell(new Identify(1));
        }

        return true;
    }

    private bool IdentifyMessageReceived(ActorIdentity obj)
    {
        return true;
    }
}

在利用集群MEMBER-UP事件的情况下,我尝试向新成员发送Identify请求,但是遇到的问题是提供的ClusterEvent.MemberUp对象不包含有关节点中的参与者,但仅包含看起来像这样的节点引用:

akka.tcp:// mycluster @ localhost:666

这很有意义,因为它是联机的节点,而不是参与者。

如果我更改代码以使用命名角色:

_actorSystem = ActorSystem.Create("mycluster");
_actoraActor = this._actorSystem.ActorOf<ActorA>("actora");

然后我可以成功查询该服务的需求。这是当您拥有一个已命名的参与者时所期望的结果,但是似乎无法从外部实际确定节点上正在运行的参与者的实例。

因此,当使用N个未命名的actor实例时,正确的步骤是什么来标识对您感兴趣的actor的引用,特别是当生成的actor没有名称时?

编辑:

我已决定重述该问题,因为最初我没有充分描述它。这个问题的正确表达是:

  

“是否有一种方法可以使当前所有实例化的actor可用   当您拥有的全部是节点路径时,从外部参与者获得的给定节点?”

在我看来,这应该是基本框架中内置的内容,除非存在我不完全理解的某种设计注意事项。

我还注意到,我认为解决我的特定问题的正确方法可能只是我正在尝试进行发布/订阅,而这种https://getakka.net/articles/clustering/distributed-publish-subscribe.html更合适。

1 个答案:

答案 0 :(得分:4)

我认为出于您的目的,您应该考虑利用参与者的层次结构。

创建一个具有硬编码名称的父级,而不是使用随机分配的名称创建顶级actor:

_actorSystem = ActorSystem.Create("mycluster");
_delegatorParent = this._actorSystem.ActorOf<ParentActorA>("parent");

此父演员可以生成任意数量的子代,并且可以响应收到的消息生成子代:

_delegatorParent.Tell(new WorkItem("someWork", 1200));

这可能导致父母创建实际执行工作的子演员:

public class ParentActorA{
    public ParentActorA(){
       Receive<WorkItem>(x => {
          // create new child to carry out the work
          var delegatorActor = Context.ActorOf<ActorA>();
          delegatorActor.Forward(x);
       });
    }
}

这为您提供了进入该节点/角色系列的固定入口点,同时仍具有启动没有特定名称的新角色的功能。只需使用静态名称查找父母,而不是执行工作的子女。

在查看时,您可能还想看看池路由器和child per entity pattern in Akka.NET