我有一个主管和一个儿童演员,其外观如下:
SupervisorActor.scala
import akka.actor.{Actor, ActorLogging, Props, Terminated}
object SupervisorActor {
def props: Props = Props(new SupervisorActor)
object KillFoo
object TerminateFoo
object RestartFoo
}
final class SupervisorActor extends Actor with ActorLogging {
import com.sweetsoft.SupervisorActor._
log.info(s"Start the actor ${self}")
private val foo = context.actorOf(FooActor.props, "FOOCHILD")
context.watch(foo)
override def receive: Receive = {
case KillFoo =>
context.stop(foo)
case Terminated(actor) =>
log.info(s"Kill actor $actor")
case TerminateFoo =>
log.info("Terminate FooActor")
foo ! new IllegalArgumentException
case RestartFoo =>
}
}
FooActor.scala
import akka.actor.SupervisorStrategy.{Escalate, Restart, Resume, Stop}
import akka.actor.{Actor, ActorLogging, OneForOneStrategy, Props}
import scala.concurrent.duration._
object FooActor {
def props: Props = Props(new FooActor)
}
final class FooActor extends Actor with ActorLogging {
log.info(s"Start the actor ${ self }")
override val supervisorStrategy: OneForOneStrategy =
OneForOneStrategy(maxNrOfRetries = 1, withinTimeRange = 1.minute) {
case _: ArithmeticException => Resume
case _: NullPointerException => Restart
case _: IllegalArgumentException =>
println("STOP exception raised.")
Stop
case _: Exception => Escalate
}
override def receive: Receive = {
case _ => log.info("I got killed.")
}
}
和Main.scala
import akka.actor.ActorSystem
import com.sweetsoft.SupervisorActor.{TerminateFoo}
import scala.concurrent.Future
import scala.io.StdIn
object Main extends App {
val system = ActorSystem("monarch")
implicit val dispatcher = system.dispatcher
try {
// Create top level supervisor
val supervisor = system.actorOf(SupervisorActor.props, "mupervisor")
// Exit the system after ENTER is pressed
Future {
Thread.sleep(2000)
supervisor ! TerminateFoo
}
StdIn.readLine()
} finally {
system.terminate()
}
}
FooActor
被杀死后,我想像手动一样再次手动重新启动它:
private val foo = context.actorOf(FooActor.props, "FOOCHILD")
如何做到?
我正在考虑创建一个函数,该函数将创建FooActor
,并在杀死它后,只需调用该函数以启动新的FooActor
。
答案 0 :(得分:4)
代码有一些问题。 supervisorStrategy
应该放在SupervisorActor
中,因为它负责监督,而不是儿童演员本身。
foo ! new IllegalArgumentException
不会导致子actor终止,因为actor可以接受任何对象作为消息,并且不对Exception派生对象进行特殊处理。它只会显示“我被杀”。但忽略该消息并继续运行。特别是,它不会调用supervisorStrategy
处理程序。
您可以:
将预定义系统PoisonPill
消息发送给子actor
优雅地停止它(即在处理所有待处理的消息之后)
将预定义系统Kill
消息发送给子actor以使其停止
处理完当前消息后立即忽略它
其他排队的消息(如果有)。
TerminateFoo
条消息转发给它
并在其处理程序中引发异常。在这种情况下,孩子
对象的命运由主管决定
IllegalArgumentException异常类型(即在您的情况下停止)。。
override def receive: Receive = {
case TerminateFoo =>
log.info("Stopping FooActor by throwing an unhandled exception for supervisorStrategy to process it")
throw new IllegalArgumentException
case m => log.info(s"I received a message $m")
}
有关详情,请参见https://doc.akka.io/docs/akka/current/actors.html#stopping-actors