如何定期执行AKKA Actor的例行程序?

时间:2014-05-22 09:30:00

标签: scala akka

我需要一个演员来阻止它的一个孩子,这样我就可以创建一个同名的新演员(UUID?)。

我有ActorSystemActor个孩子。这个孩子用context.actorOfcontext.watch创造了新的演员。当我尝试使用context.stop停止其中一个时,我发现它的postStop方法按预期被调用,但无论我等待多久(秒......分钟......),它从不将Terminated消息发回给其创建者(并观看)演员。

我在AKKA文档中读到了这个:

  

由于停止一个actor是异步的,你不能立即重用你刚刚停止的孩子的名字;这将导致InvalidActorNameException。相反,观察终止参与者并创建其替换以响应最终到达的终止消息。

我不在乎等待正常终止,但我真的需要演员最终在被要求时终止。我错过了什么吗?我应该直接从系统而不是演员创建演员吗?

编辑:

这是我的代码:

object MyApp extends App {
  def start() = {
    val system = ActorSystem("MySystem")
    val supervisor = system.actorOf(Supervisor.props(), name = "Supervisor")
  }

  override def main(args: Array[String]) {
    start()
  }
}

object Supervisor {
  def props(): Props = Props(new Supervisor())
}

case class Supervisor() extends Actor {
  private var actor: ActorRef = null

  start()

  def newActor(name: String): ActorRef = {
    try {
      actor = context.actorOf(MyActor.props(name), name)
      context.watch(actor)
    } catch {
      case iane: InvalidActorNameException =>
        println(name + " not terminated yet.")
      null
    }
  }

  def terminateActor() {
    if (actor != null) context.stop(actor)
    actor = null
  }

  def start() {
    while (true) {
      // do something
      terminateActor()
      newActor("new name possibly same name as a previously terminated one")
      Thread.sleep(5000)
    }
  }

  override def receive = {
    case Terminated(x) => println("Received termination confirmation: " + x)
    case _ => println("Unexpected message.")
  }

  override def postStop = {
    println("Supervisor called postStop().")
  }
}

object MyActor {
  def props(name: String): Props = Props(new MyActor(name))
}

case class MyActor(name: String) extends Actor {
  run()

  def run() = {
    // do something
  }

  override def receive = {
    case _ => ()
  }

  override def postStop {
    println(name + " called postStop().")
  }
}

EDIT²:正如@DanGetz所提到的,人们不需要在AKKA演员中调用Thread.sleep。我需要的是一个定期的例程。这可以使用AKKA上下文调度程序完成。见:http://doc.akka.io/docs/akka/2.3.3/scala/howto.html#scheduling-periodic-messages。相反,我在一个无限循环中阻止了actor,阻止它使用它的异步机制(消息)。我改变了标题,因为问题实际上并没有涉及演员终止。

1 个答案:

答案 0 :(得分:4)

现在这个问题已经发生了一些变化,很难准确估计出你想要的东西,但无论如何我都会采取刺激措施。下面你会看到你的代码的修改版本,它既显示了一个任务的定期安排(一个启动了孩子终止过程),也显示了一个孩子,当我们确定前一个孩子时,只创建一个具有相同名称的新孩子。已经停止。如果你运行下面的代码,你应该看到它杀死了孩子并等待终止消息,然后再说明具有完全相同名称的新代码。我希望这就是你要找的东西:

object Supervisor {
  val ChildName = "foo"
  def props(): Props = Props(new Supervisor())
  case class TerminateChild(name:String)
}

case class Supervisor() extends Actor {
  import Supervisor._
  import scala.concurrent.duration._
  import context._

  //Start child upon creation of this actor
  newActor(ChildName)

  override def preStart = {
    //Schedule regular job to run every 5 seconds
    context.system.scheduler.schedule(5 seconds, 5 seconds, self, TerminateChild(ChildName))
  }

  def newActor(name: String): ActorRef = {
    val child = context.actorOf(MyActor.props(name), name)
    watch(child)
    println(s"created child for name $name")
    child
  }

  def terminateActor(name:String) = context.child(ChildName).foreach{ ref =>
    println(s"terminating child for name $name")
    context stop ref
  }

  override def receive = {
    case TerminateChild(name) =>
      terminateActor(name)

    case Terminated(x) => 
      println("Received termination confirmation: " + x)
      newActor(ChildName)

    case _ => println("Unexpected message.")
  }

  override def postStop = {
    println("Supervisor called postStop().")
  }
}