scala - 如何重新启动被杀死的演员?
问题描述
我有一个主管和一个儿童演员,如下所示:
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
.
解决方案
代码存在一些问题。supervisorStrategy
应该由SupervisorActor
它负责监督,而不是儿童演员本身。
foo ! new IllegalArgumentException
不会导致子actor终止,因为actor可以接受任何对象作为消息并且异常派生对象不会被特殊处理。它只会打印“我被杀了”。但否则忽略该消息并继续运行。特别是,它不会调用 supervisorStrategy 处理程序。
您可以:
将预定义的系统
PoisonPill
消息发送给子actor以优雅地停止它(即在处理所有待处理消息之后)将预定义的系统
Kill
消息发送给子actor以在处理当前消息后立即停止它,并忽略其他排队的消息(如果有)。- 将
TerminateFoo
消息转发给它并在其处理程序中引发异常。在这种情况下,子对象的命运由 IllegalArgumentException 异常类型的 supervisorStrategy 处理程序决定(即在您的情况下为停止)。
.
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
推荐阅读
- git - 将 SSH 与 Git 一起使用时权限被拒绝(公钥)
- frontend - “软件开发”和“后端开发”之间的 5 个区别可以澄清混淆
- excel - 在 Excel VBA 或公式中搜索并返回
- javascript - 正则表达式在以表达式开头的每一行中捕获多个匹配项
- julia - Julia:一定要使用包的开发版本
- mysql - 使用查询将数据从 EXCEL/CSV 加载到 MYSQL?
- r - 房东尝试使用 readSDMX 包读取 ABS.gov 每周租金数据
- python - 从python将数据推送到sql server时如何避免bcpy中的dbo(批量复制python)
- cmake - CMake:如何在目标之间重用源文件定义而不重复?
- python - 如何创建一个字典,其键为整数,定义为 numpy 数组?