Akka:Akka重启后的消息排序

时间:2016-06-07 15:32:16

标签: akka

以下代码示例(您可以复制并运行)显示创建MyParentActor的{​​{1}}。

MyChildActor为其第一条消息引发异常,导致重启。

但是,我想要实现的是在重新启动MyChildActor时仍然在“消息2”之前处理“消息1”。

相反,正在发生的事情是将消息1添加到邮箱队列的尾部,因此首先处理消息2。

如何在重新启动演员时实现原始消息的排序,而无需创建自己的邮箱等?

MyChildActor

1 个答案:

答案 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)
}