How to find out if an actor is free

I have an unknown number of tasks that will be performed by a known (of course) number of participants. The initial task number may increase after the actor completes the task. That is, after completing his task, the actor could add a new task to perform.

The way I handle this is for each actor to send a message back to the master when he has completed his task, not only with the result of the execution, but also with a “flag” indicating that the actor is idle now. The master has a queue of tasks and a queue of inactive participants, every time an actor sends a message "filled with a task", the master checks if there is anything else for this actor ... so on and so on, until the task queue is empty, and Idle queue is full ... at this point I am shutting down the system. There is not much control here, so I feel like I am not doing it properly ...

I do not use a router because I could not find a way to request a router for unoccupied participants, so my question is:

What is the “right” way to deal with the situation described above in Akka?

+8
java actor akka
source share
3 answers

You should take a look at Akka Routing Capabilities. SmallestMailboxRouter may be what you are looking for.

Alternatively, you can simply create actors on demand, i.e. For each task, a new actor is dynamically created. The central actor keeps track of all current actors. After the working actor is completed, he sends PoisonPill and informs the owner about its shutdown (actively or through the standard Terminate message, which Akka will send to the controlling player). When there are no active active participants, i.e. More tasks, an actor-performer shuts down the system.

Adding after reading the comment: Take a look at the sources of SmallestMailboxLike , a Scala mixed in SmallestMailboxRouter . Warning: you must have basic Scala knowledge. But this is generally a good idea if you want to use Akka ... The isProcessingMessage(ActorRef) method can be understood as 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 } 
+7
source share

Another strategy might be to use BalancingDispatcher and RoundRobinRouter (as a pool actor). From the Akka docs:

 BalancingDispatcher # This is an executor based event driven dispatcher that will try to redistribute 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 

Define your dispatcher in application.conf or load it programmatically at startup.

 private final static Config akkaConfig = ConfigFactory.parseString( "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 " ); 

Then define a router and dispatcher for routes.

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

Thus, the router will simply continue to “distribute” messages, and the dispatcher will start the selected actor (and he also performs theft of work).

+1
source share

Balancing Manager will use only one mailbox for all created members that are all created using BalancingDispatcher. This will simplify your work.

-one
source share

All Articles