The Worker Nodes

Worker actors and the Master actor interact as follows:

  1. Worker actors register with the Master so the master knows they are available and ready to take on work.
  2. When the Master actor has work, it sends a ‘WorkIsReady’ message to all workers it things are not busy. Worker actors that are idle will reply to the Master with a WorkerRequestsWork message.
  3. The Master picks the first reply and assigns the work to that worker. This achieves back pressure because the Master does not push work on workers that are already busy and overwhelm their mailboxes.
  4. When the worker receives work from the master, it delegates the actual processing to a child actor, WorkExecutor. This allows the worker to be responsive while its child executes the work.

Master to Worker Message Flow

You can see how a worker node and a number of worker actors is started in the method Main.startWorker:

def startWorker(port: Int, workers: Int): Unit = {
  val system = ActorSystem("ClusterSystem", config(port, "worker"))
  val masterProxy = system.actorOf(
    MasterSingleton.proxyProps(system),
    name = "masterProxy")

  (1 to workers).foreach(n =>
    system.actorOf(Worker.props(masterProxy), s"worker-$n")
  )
}

Now that we have covered all the details, we can experiment with different sets of nodes for the cluster.