Comment savoir si un acteur est inactif

J’ai un nombre inconnu de tâches à exécuter par un nombre connu (bien sûr) d’acteurs. Le nombre de tâches initiales peut augmenter lorsqu’un acteur termine une tâche. C’est-à-dire qu’un acteur, à la fin de sa tâche, peut append un nouveau travail à exécuter.

Pour y remédier, chaque acteur doit renvoyer un message au maître une fois son travail terminé, non seulement avec le résultat de l’exécution, mais également avec un “indicateur” indiquant que l’acteur est maintenant inactif. Le maître a une queue de travaux et une file d’acteurs inactifs. Lorsqu’un acteur envoie un message indiquant que le travail est terminé, le maître vérifie s’il a autre chose à faire pour cet acteur … ainsi de suite jusqu’à la queue des travaux. est vide et la queue des inactifs est pleine … à ce moment-là, je ferme le système. Il n’y a pas beaucoup de supervision ici, alors je sens que je ne le fais pas correctement …

Je n’utilise pas de routeur car je ne pouvais pas trouver le moyen d’interroger le routeur pour connaître les acteurs inactifs. Ma question est la suivante:

Quelle est la “bonne” façon de gérer la situation que je viens de décrire à Akka?

Vous devriez jeter un coup d’œil aux capacités de routage d’Akka. SmallestMailboxRouter peut être ce que vous recherchez.

Au lieu de cela, vous pouvez simplement créer des acteurs à la demande, c’est-à-dire que pour chaque tâche, un nouvel acteur est créé de manière dynamic. Un acteur central garde la trace de tous les acteurs actuellement actifs. Une fois qu’un acteur a terminé son travail, il s’envoie lui-même un PoisonPill et informe le maître de son arrêt (activement ou via le message standard Terminate qu’Akka enverra à l’acteur superviseur). Lorsqu’il n’y a plus d’acteurs actifs, c’est-à-dire plus de tâches, l’acteur contrôleur ferme le système.

Ajout après la lecture du commentaire: Jetez un coup d’œil aux sources de SmallestMailboxLike , un trait Scala mélangé par SmallestMailboxRouter . Attention: vous devez avoir une connaissance de base de Scala. Mais c’est de toute façon une bonne idée si vous voulez utiliser Akka … La méthode isProcessingMessage(ActorRef) peut être comprise de la manière isNotIdle(ActorRef)

 // Returns true if the actor is currently processing a message. // It will always return false for remote actors. // Method is exposed to subclasses to be able to implement custom // routers based on mailbox and actor internal state. protected def isProcessingMessage(a: ActorRef): Boolean = a match { case x: LocalActorRef ? val cell = x.underlying cell.mailbox.isScheduled && cell.currentMessage != null case _ ? false } // Returns true if the actor currently has any pending messages // in the mailbox, ie the mailbox is not empty. // It will always return false for remote actors. // Method is exposed to subclasses to be able to implement custom // routers based on mailbox and actor internal state. protected def hasMessages(a: ActorRef): Boolean = a match { case x: LocalActorRef ? x.underlying.mailbox.hasMessages case _ ? false } 

Une autre stratégie peut consister à utiliser un BalancingDispatcher et un RoundRobinRouter (en tant qu’acteur “pool”). De la documentation Akka:

 BalancingDispatcher # This is an executor based event driven dispatcher that will try to redissortingbute work from busy actors to idle actors. # All the actors share a single Mailbox that they get their messages from. It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; ie the actors belong to a pool of actors, and to the client there is no guarantee about which actor instance actually processes a given message. # Sharability: Actors of the same type only # Mailboxes: Any, creates one for all Actors # Use cases: Work-sharing 

Définissez votre répartiteur dans application.conf ou chargez-le par programme au démarrage.

 private final static Config akkaConfig = ConfigFactory.parseSsortingng( "my-dispatcher.type = BalancingDispatcher \n" + "my-dispatcher.executor = fork-join-executor \n" + "my-dispatcher.fork-join-executor.parallelism-min = 8 \n" + "my-dispatcher.fork-join-executor.parallelism-factor = 3.0 \n" + "my-dispatcher.fork-join-executor.parallelism-max = 64 " ); 

Ensuite, définissez le routeur et le répartiteur pour les routes.

 getContext().actorOf(new Props(MyActor.class).withRouter(new RoundRobinRouter(10)).withDispatcher("my-dispatcher"), "myActor"); 

Ainsi, le routeur continuera simplement à “dissortingbuer” les messages et le répartiteur exécutera un acteur sélectionné (et implémentera également le vol de travail)

Le répartiteur d’équilibrage utilisera une seule boîte aux lettres pour tous les acteurs créés qui sont tous créés avec BalancingDispatcher. Cela simplifiera donc votre travail.