akka.netakka.net-cluster

akka.net cluster : how to send message from seed node to non-seed node


I am new to akka.net. I have 2 .net core2 console apps in a cluster , trying to send message from actor from one console app [ which is seed node ] to remote actor on another console app [which is non-seed node].

After starting/running both the console apps, the cluster is established and both the nodes are Up and seed node knows about the non-seed node and vice-versa, but no message is received by remote actor that is on the non-seed node. I am creating a round-robin router on the seed-node, but not sure what I am missing?

Please guide.

Below is the sample code of the both the apps i.e seed node and non-seed node.

// .net core2 console App with Seed Node

class Program
{
    public static ActorSystem ClusterSystem;
    private static IActorRef StartActor;
    private static void Main(string[] args)
    {
        var config = ConfigurationFactory.ParseString(@"
akka
{
actor {
    provider=cluster
    deployment {
    /tasker {
      router = round-robin-pool # routing strategy
      nr-of-instances = 5 # max number of total routees
      cluster {
         enabled = on
         allow-local-routees = off
         use-role = tasker
         max-nr-of-instances-per-node = 1
      }
    }
  }
 }
remote
    {
    dot-netty.tcp {
      port = 8081
      hostname = ""localhost""
    }
}
cluster {
    seed-nodes = [""akka.tcp://ClusterSystem@localhost:8081""]
    roles=[""main""]
    }
}

        ClusterSystem = ActorSystem.Create("ClusterSystem", config);
        var taskActor = ClusterSystem.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "tasker");
        StartActor = ClusterSystem.ActorOf(Props.Create(() => new StartActor(taskActor)), "startactor");
        StartActor.Tell(new Initiate()); // call local actor

// actor on seed node (local actor)

class StartActor : ReceiveActor, ILogReceive
{
    private IActorRef taskActor;
    public StartActor(IActorRef router)
    {
        this.taskActor = router;
        Receive<Initiate>(i => Start(i));
    }
    private void Start(Initiate initiate)
    {
        taskActor.Tell(new Initiate()); // calling remote actor
    }
}

.net core2 Console app with Non seed node

class Program
{
    public static ActorSystem ClusterSystem;
    public static IActorRef TaskActor;

    private static void Main(string[] args)
    {
        Console.Title = "BackEnd";
        var config = ConfigurationFactory.ParseString(@"
akka
{
actor {
provider=cluster
    }
remote
    {
    dot-netty.tcp {
    port = 0
    hostname = ""localhost""
    }
}
cluster {
    seed-nodes = [""akka.tcp://ClusterSystem@localhost:8081""]
    roles=[""tasker""]
    }
}
");

ClusterSystem = ActorSystem.Create("ClusterSystem", config);
        TaskActor = ClusterSystem.ActorOf(Props.Create<TaskActor>(), "tasker");
        Console.Read();
    }
}

// Actor on Non-seed node (Remote Actor)

class TaskActor : ReceiveActor, ILogReceive
{
    private readonly IActorRef manager;
    public TaskActor()
    {
        this.Receive<Initiate>(i => this.Init(i));
    }
    private void Init(Initiate initiate)
    {
        Console.WriteLine($"Message Received"); //
    }
  }

Solution

  • I am myself answering to my question. So the first thing is that since the remote actor is created by/in another console application, the deployment configuration needs to be changed with routing strategy to "round robin group"

    /tasker {
          router = round-robin-group # routing strategy
            routees.paths = [""/user/starter""]
            nr-of-instances = 5 # max number of total routees
          cluster {
             enabled = on
             allow-local-routees = off
             use-role = tasker
          }
        }
    

    And the the "startActor" from the seed node need to be as below

    class StartActor : ReceiveActor, ILogReceive
    {
        private IActorRef router, self;
    
        public StartActor(IActorRef router)
        {
            self = Self;
            this.router = router;
    
            Receive<Initiate>(i =>
            {
                var routee = router.Ask<Routees>(new GetRoutees()).ContinueWith(tr =>
                {
                    if (tr.Result.Members.Count() > 0)
                    {
                        Start(i);
                    }
                    else
                    {
                        self.Tell(i);
                    }
                });
            });
        }
    
        private void Start(Initiate initiate)
        {
            router.Tell(initiate);
        }
    }
    

    The above code within the "startActor" looks for the routees which once received then only the message is sent otherwise the message is blasted and not received by the remote actor.