Actor生命周期
Actor的生命周期是使用Hooks体现和控制的,我们可以重写相关的Hooks,从而实现对Actor生命周期各环节的细粒度控制,各种Hook顺序关系如下图:
prestart():
在构造函数之后调用,重启时不会执行。postStop():
在重启之前调用,异常重启时不会执行。preRestart(reason, message):
在 actor 异常重启前保存当前状态,默认情况下会调用 postStop()。postRestart():
在 actor 异常重启后恢复重启前保存的状态,默认情况下会调用 preStart()。
示例代码
ParentActor.scala :接收从 Main.scala 里发送的消息,初始化或控制 ChildActor。
package com.lp.akka.notes.lifecycle
import akka.actor.{
Actor, ActorLogging, Props, ReceiveTimeout}
/**
* @author li.pan
* @version 1.0.0
* @Description 父Actor
* @createTime 2021年01月13日 13:04:00
*/
class ParentActor extends Actor with ActorLogging {
println("start pActor ")
def receive = {
case "test" => log.info("received test")
case ("newChild", name: String) => context.actorOf(Props[ChildActor], name)
case ("stop", name: String) => {
val child = context.actorFor(self.path + "/" + name);
context.stop(child)
}
case ReceiveTimeout => throw new RuntimeException("received timeout"); // 每隔超时时间没收到消息就抛出异常
case "suicide" =>
case x: Any => log.info("received unknown message :" + x)
}
/**
* 在 actor 实例化后执行,重启时不会执行
*/
override def preStart {
println("actor:" + self.path + ", parent preStart ")
}
/**
* 在 actor 正常终止后执行,异常重启时不会执行。
*/
override def postStop {
println("actor:" + self.path + ",parent postStop .")
}
/**
* 在 actor 异常重启前保存状态
*/
override def preRestart(reason: Throwable, message: Option[Any]) {
println("actor:" + self.path + ", preRestart parent, reason:" + reason + ", message:" + message)
}
/**
* 在 actor 异常重启后恢复状态
*/
override def postRestart(reason: Throwable) {
println("actor:" + self.path + ", postRestart parent, reason:" + reason)
}
}
ChildActor.scala:子 Actor,被 ParentActor 控制。
package com.lp.akka.notes.lifecycle
import akka.actor.Actor
/**
* @author li.pan
* @version 1.0.0
* @Description 子 Actor
* @createTime 2021年01月13日 13:03:00
*/
class ChildActor extends Actor {
override def receive() = {
case "abc" => println("get abc string ")
case "exception" => throw new NullPointerException()
case _ => println("children cann't handle unknown message")
}
override def preStart {
println("actor:" + self.path + ",child preStart .")
}
override def postStop {
println("actor:" + self.path + ",child postStop .")
}
override def preRestart(reason: Throwable, message: Option[Any]) {
println("actor:" + self.path + ",preRestart child, reason:" + reason + ", message:" + message)
}
override def postRestart(reason: Throwable) {
println("actor:" + self.path + ",postRestart child, reason:" + reason)
}
}
LifeCycleMainApp:初始化、发送消息给Actor。
package com.lp.akka.notes.lifecycle
import akka.actor.{
ActorSystem, Kill, Props}
/**
* @author li.pan
* @version 1.0.0
* @Description 主类
* @createTime 2021年01月13日 13:05:00
*/
object LifeCycleMainApp extends App {
// 构建Actor系统
val system = ActorSystem("lpLocalSys")
// 通过Props方式创建父Actor
val pActor = system.actorOf(Props[ParentActor], name = "pActor")
pActor ! ("newChild", "child-1")
pActor ! ("newChild", "child-2")
pActor ! "test"
val parent = system.actorSelection("akka://lpLocalSys/user/pActor")
parent ! "test"
// parent ! ("stop", "child-2")
val child2 = system.actorSelection("akka://lpLocalSys/user/pActor/child-2")
child2 ! Kill // 杀死 child2
// child2 ! "exception"
Thread.sleep(5000) // 等待 child2 被杀死
pActor ! ("newChild", "child-2")
// Thread.sleep(5000)
// myActor ! ("newChild", "child-2")
}
运行结果:
在 LifeCycleMainApp 里,如果不等的 child-2 被杀死就创建同名的 actor将导致名为 myactor 的父 actor 异常,使它重启,而根据 Akka Actor 的监管策略,它也会重启它的子 Actor,所以 child-1 和child-2 也会被重启,输出如下
从输出可以看到:父 Actor 首先调用 preRestart ,然后 被实例化,再调用 postRestart,最后再重启它的子 Actor,子 Actor 也遵循上述的步骤。
参考文献
- 《Akka入门与实践》
- https://coderbee.net/index.php/akka/20140814/1000
- https://www.jianshu.com/p/16de393ec5b4
关注公众号 回复Akka
领取《Akka入门与实践》书籍
关注公众号 数据工匠记
,专注于大数据领域离线、实时技术干货定期分享!个人网站 www.lllpan.top