An actor who is waiting for the completion of all tasks in children before leaving

It is impossible to figure out how to solve the following problem: I have several participants (workers) who somehow perform tasks when they receive (I mean them). The main actor (master) controls this process and can get the task to stop work. In this case, the main actor should stop creating new tasks and wait for the employees to finish all existing tasks, and only then should the main actor exit.

import actors.Actor
import actors.Actor._

class Foreman extends Actor{
  val workerA = new WorkerA
  val workerB = new WorkerB
  val workerC = new WorkerC
  self.link(workerA)
  self.link(workerB)
  self.link(workerC)
  def act{
    workerA.start
    workerB.start
    workerC.start

    // adding tasks to workers somehow
    //...
    loop{
      case ResultOfTask(res) => //...
      case Stop => //workers mustn't immediately stop but must finish their tasks and then exit
      case ProductionAccident => //...
    }


  }
}

case class Task(activity:String)
case class ResultOfTask(result:String)

trait Worker extends Actor{

  def act{
    loop{
      react{
        case Task(activity) => sender ! processTask(activity)
      }
    }
  }

  def processTask(activity:String):ResultOfTask
}

To solve this problem, I wrote the following code:

def condition = workerA.getState!=State.Suspended  && workerB.getState!=State.Suspended && workerC.getState!=State.Suspended && mailboxSize == 0
case Stop => {
  if(condition) exit("sweet dreams") else continue
}

to check if the main actor should come out. Another option is to have a tender in the "Worker" line, increase it when the employee receives a message and decrement when he is reponing.

trait Worker extends Actor {
  private var count = 0
  def act {
    loop{
      react{
        case Task(activity) => {
          count += 1
          sender ! processTask(activity)
          count -= 1
        }
      }
    }
  }
  def hasDoneAllTasks = count == 0

  def processTask(activity: String): ResultOfTask
}

And the "condition" function in "Foreman" will be

def condition = workerA.hasDoneAllTasks   && workerB.hasDoneAllTasks  && workerC.hasDoneAllTasks  && mailboxSize == 0

, , .

+3
4

, : , , , , , , . , , ( , ).

, ,

case object Done { }

, . , . .

, , , , .

case object RequestStop { }

- Done, . Done, RequestStop s, .

+1

Foreman ? , , . , , , . , .

+1

- .

, , ,

class Foreman extends Actor{

  var numTasks: Int = 0
  var shouldExit = false

  def act = loop {
   react {
     case t: Task =>
       if (!shouldExit)  {
         numTasks += 1
         selectWorker ! t
       } else {
         // send some kind of error status to sender
       }
     case ResultOfTask(rest) =>
       numTasks -= 1
       // ....
       if (numTasks == 0 && shouldExit) exit
     case Stop() => shoudExit = true
}

, , ,

  def act = loop {
   reactWithin(0) {
     case Stop() => shouldStop = true
     case TIMEOUT => react {
       case t: Task =>
         if (!shouldExit)  {
           numTasks += 1
           selectWorker ! t
         } else {
           // send some kind of error status to sender
         }
       case ResultOfTask(rest) =>
         numTasks -= 1
         // ....
         if (numTasks == 0 && shouldExit) exit
       case Stop() => shoudExit = true
  }
}
+1

, , - trapExit, case Exit exit, system. trapExit true:

// Foreman

def act() {
  trapExit = true
  link(workerA)
  link(workerB)
  ...
}

, - "", , :

// Foreman

def act() {
  ....
  loop { react {
    case Exit (worker: Actor, reason: AnyRef) => {
      // decrement counter, or list of workers, and exit if empty
    }
    ...
   }}
}

reason. , , , :

// Worker:

exit(WorkComplete)
exit(Emergency)

.. .. , Exit, . , - :

// Foreman

def act() {
  ....
  loop { react {
    case Exit (worker: Actor, reason: WorkComplete) => {
      // decrement counter, or list of workers, and exit if empty
    }

    case Exit (worker: Actor, reason: TasksExhausted) => {
      // log something, or make shut down worker if too many are exhausted
    }

    case Exit (worker: Actor, reason: Exception) => {
      // log the exception, then restart the actor
    }

    ...
   }}
}

It is not clear from your initial question whether you want the workers to continue to work even when they are finished, until the team leader tells them that they should leave when this time. If this is the case, sending employees messages telling them to "exit when finished" works, and you can say that they finished using the trapExit mechanism.

Hope this caused an interesting solution!

+1
source

Source: https://habr.com/ru/post/1790957/


All Articles