以下代码示例(您可以复制并运行)显示创建MyParentActor
的{{1}}。
MyChildActor
为其第一条消息引发异常,导致重启。
但是,我想要实现的是在重新启动MyChildActor
时仍然在“消息2”之前处理“消息1”。
相反,正在发生的事情是将消息1添加到邮箱队列的尾部,因此首先处理消息2。
如何在重新启动演员时实现原始消息的排序,而无需创建自己的邮箱等?
MyChildActor
答案 0 :(得分:1)
您可以使用特殊信封标记失败的消息,并将所有内容存储到接收该消息(请参阅子actor实现)。只需定义一个行为,其中actor隐藏除了特定包络之外的每个消息,处理它的有效负载,然后释放所有其他消息并返回到它的正常行为。
这给了我:
INFO TestApp$MyChildActor - Received message Message 1
INFO TestApp$MyChildActor - Received message Message 2
object TestApp extends App {
var count = 0
val actorSystem = ActorSystem()
val parentActor = actorSystem.actorOf(Props(classOf[MyParentActor]))
parentActor ! "Message 1"
parentActor ! "Message 2"
class MyParentActor extends Actor with ActorLogging{
var childActor: ActorRef = null
@throws[Exception](classOf[Exception])
override def preStart(): Unit = {
childActor = context.actorOf(Props(classOf[MyChildActor]))
}
override def receive = {
case message: Any => {
childActor ! message
}
}
override def supervisorStrategy: SupervisorStrategy = {
OneForOneStrategy() {
case e: CustomException => Restart
case _: Exception => Restart
}
}
}
class MyChildActor extends Actor with Stash with ActorLogging{
override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
message match {
case Some(e) =>
self ! Unstash(e)
}
}
override def postRestart(reason: Throwable): Unit = {
context.become(stashing)
preStart()
}
override def receive = {
case message: String => {
if (count == 0) {
count += 1
throw new CustomException("Exception occurred")
}
log.info("Received message {}", message)
}
}
private def stashing: Receive = {
case Unstash( payload ) =>
receive(payload)
unstashAll()
context.unbecome()
case m =>
stash()
}
}
case class Unstash( payload: Any )
class CustomException(message: String) extends RuntimeException(message)
}