我需要一个演员来阻止它的一个孩子,这样我就可以创建一个同名的新演员(UUID?)。
我有ActorSystem
个Actor
个孩子。这个孩子用context.actorOf
和context.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,阻止它使用它的异步机制(消息)。我改变了标题,因为问题实际上并没有涉及演员终止。
答案 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().")
}
}