6

我的应用程序中有以下代码,它在我的集群中创建了一个 Akka.NET 角色的实例,如下所示:

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

请注意,我故意省略了 name 属性,因为我打算创建 N 个 ActorA 类型的演员并且不想管理名称。运行上面的代码,我最终得到一个具有如下 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 个未命名演员的实例时,识别对您感兴趣的演员的引用的正确步骤是什么,特别是当演员生成时没有名字?

编辑:

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

“当你只有节点路径时,有没有办法从外部参与者获取给定节点上当前可用的所有实例化参与者?”

对我来说,这似乎应该是基本框架中内置的东西,除非有某种我不完全理解的设计考虑。

我还注意到,我认为解决我的特定问题的正确方法可能只是我正在尝试做一个 Pub/Sub 而这个https://getakka.net/articles/clustering/distributed-publish-subscribe.html是更合适。

4

1 回答 1

6

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

与其使用随机分配的名称创建顶级actor,不如使用硬编码名称创建父级:

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

这个父actor可以生成任意数量的子actor,并且它可以生成子actor来响应传入的消息:

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

这可能会导致父级创建一个实际执行工作的子级actor:

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

这为您提供了进入此节点/演员系列的固定入口点,同时仍然能够启动没有特定名称的新演员。只需使用静态名称查找父级,而不是执行工作的子级。

当您使用它时,您可能还想看看Akka.NET 中的池路由器和每个实体模式的子节点

于 2018-06-27T14:00:06.427 回答