Search code examples
akka.netakka.net-cluster

Replying an Ask in a clustered routee


I am creating a project that at this moment has an Actor (User) that calls to another actor (Concert) through a consistent-hash-group router. All works fine but my problem is that from the concert actor I can not answer the Ask message. Somehow the message is lost and nothing happens in the client. I have tried everything with no luck:

  • Sender.Tell <-- creates a temporal? sender
  • Passing the User IActorRef by reference in the message and using it.

Here is the full code: https://github.com/pablocastilla/AkkaConcert

The main details are the following:

User actor:

        protected IActorRef concertRouter;


    public User(IActorRef concertRouter, int eventId)
    {
        this.concertRouter = concertRouter;
        this.eventId = eventId;

        JobStarter = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.FromMilliseconds(20),
                     TimeSpan.FromMilliseconds(1000), Self, new AttemptToStartJob(), Self);

        Receive<AttemptToStartJob>(start =>
        {
            var self = Self;

            concertRouter.Ask<Routees>(new GetRoutees()).ContinueWith(tr =>
            {
                if (tr.Result.Members.Count() > 0)
                {
                    var m = new GetAvailableSeats() { User = self, ConcertId = eventId };

                    self.Tell(m);

                    //                        JobStarter.Cancel();                      

                }

            }, TaskContinuationOptions.ExecuteSynchronously);
        });

        Receive<GetAvailableSeats>(rs =>
        {
            rs.User = Self;

            //get free seats
            concertRouter.Ask(rs).ContinueWith(t=>
            {
                Console.WriteLine("response received!!");

            }
            );
        });

Client HOCON configuration:

  <akka>
<hocon>
  <![CDATA[
                akka {
          actor {

                        provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
                        deployment {


                            /eventpool {
                                router = consistent-hashing-group
              routees.paths = ["/user/HugeEvent"]                                   
                                virtual-nodes-factor = 8
                                cluster {
                                        enabled = on
                                        max-nr-of-instances-per-node = 2
                                        allow-local-routees = off
                                        use-role = cluster
                                }
                            }                
                        }
                    }


                    remote {
                        log-remote-lifecycle-events = DEBUG

                        helios.tcp {
                            transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
                            applied-adapters = []
                            transport-protocol = tcp
                            #will be populated with a dynamic host-name at runtime if left uncommented
                            #public-hostname = "POPULATE STATIC IP HERE"
                            hostname = "127.0.0.1"
                            port = 0
                        }
                    }            

                    cluster {
                        #will inject this node as a self-seed node at run-time
                        seed-nodes = ["akka.tcp://akkaconcert@127.0.0.1:8080"] #manually populate other seed nodes here, i.e. "akka.tcp://lighthouse@127.0.0.1:4053", "akka.tcp://lighthouse@127.0.0.1:4044"
                        roles = [client]
                        auto-down-unreachable-after = 60s
                    }
                }
        ]]>
</hocon>

In the backend side:

The actor is created

   private ActorSystem actorSystem;

    private IActorRef event1;

    public bool Start(HostControl hostControl)
    {
        actorSystem = ActorSystem.Create("akkaconcert");

        SqlServerPersistence.Init(actorSystem);

        event1 = actorSystem.ActorOf(
                Props.Create(() => new Concert(1,100000)), "HugeEvent");

        return true;
    }

Concert actor message processing

        private void ReadyCommands()
    {
        Command<GetAvailableSeats>(message => GetFreeSeatsHandler(message));

        Command<ReserveSeats>(message => ReserveSeatsHandler(message));

        Command<BuySeats>(message => Persist(message, BuySeatsHandler));


    }

    private bool GetFreeSeatsHandler(GetAvailableSeats message)
    {          

        var freeSeats = seats.Where(s => s.Value.State == Actors.Seat.SeatState.Free).Select(s2 => s2.Value).ToList();

        //1. Trying passing the user actor
        //message.User.Tell(new GetFreeSeatsResponse() { FreeSeats = freeSeats }, Context.Self);

        //2. Trying with the sender
        Context.Sender.Tell(new GetAvailableSeatsResponse() { FreeSeats = freeSeats }, Context.Self);


        printMessagesPerSecond(messagesReceived++);
        printfreeSeats(freeSeats);

        return true;
    }

HOCON config at backend side:

  <akka>
<hocon>
  <![CDATA[
                akka {
                    actor {
                        provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"

                    }

                    remote {
                        log-remote-lifecycle-events = DEBUG

                        helios.tcp {
                            transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"
                            applied-adapters = []
                            transport-protocol = tcp
                            #will be populated with a dynamic host-name at runtime if left uncommented
                            #public-hostname = "POPULATE STATIC IP HERE"
                            hostname = "127.0.0.1"
                            port = 8080
                        }
                    }            

                    cluster {
                        #will inject this node as a self-seed node at run-time
                        seed-nodes = ["akka.tcp://akkaconcert@127.0.0.1:8080"] #manually populate other seed nodes here, i.e. "akka.tcp://lighthouse@127.0.0.1:4053", "akka.tcp://lighthouse@127.0.0.1:4044"
                        roles = [cluster]
                        auto-down-unreachable-after = 10s
                    }
                }
        ]]>
</hocon>

Thanks!


Solution

  • The problem comes because of message sizes, the message was too big and it was dropped.

    Configuration for receiving bigger messages:

    akka {
    helios.tcp {
        # Maximum frame size: 4 MB
        maximum-frame-size = 4000000b
    }
    

    }