簡體   English   中英

Akka:我怎樣才能在另一個(非孩子)演員中捕捉到一個演員的失敗?

[英]Akka: how can I catch failure of one actor inside another (non child) actor?

我有兩個演員:

處理系統中某些進程的ProcessManager (例如,用戶注冊,購買等)

通知程序 - 如果ProcessManager中發生了某些錯誤,則應通知用戶。 我需要捕獲ProcessManager actor的失敗(它失敗並因任何原因而停止,例如,因為ActorInitializationException或達到最大重啟時間並且進程管理器actor被停止)。

   class ProcessManager extends Actor {
      override def receive: Receive = {
        ...
      }
    }

    class Notifier extends Actor {
      override def receive: Receive = {
        PROCESS MANAGER ACTOR FAILED AND STOPPED =>
          // Here I need to catch failure of ProcessManager actor
          // (it was failed and stopped for what ever
          // reason, for example, because of ActorInitializationException
          // or max restart time reached and Process manager actor was stopped).
          //
          // Then do some stuff, for example, send message to the client via web socket.
      }
    }


    class MyController @Inject() (cc: ControllerComponents, actorSystem: ActorSystem)
      (implicit exec: ExecutionContext) extends AbstractController(cc)  {


      // I need to catch failure of processManager in this actor.
      val notifier = actorSystem.actorOf(Props(classOf[Notifier]))

      def registerUser = Action.async {         

          // Actor may be stopped because of ActorInitializationException here
          val processManager = actorSystem.actorOf(Props(classOf[ProcessManager]))
              ...

         // OR it may be stopped here for any reason.
         processManager ! "some message which will fail and stop pm actor"

         Future.successfull(Ok("Thanks."))   
       }
   }

如何在Notifier actor中捕獲ProcessManager actor的終止(因為失敗)?

編輯讓我解釋一下我的問題的背景。

我正在Play控制器中創建PM演員並將消息發送給它(Tell),我立即向用戶返回Ok響應。 PM actor創建另一個子actor,在創建過程中拋出ActorInitializationException。 我需要通知用戶(通過Web套接字,使用Notifier actor),出現問題。

ProcessManager actor永久停止時,您可以使用DeathWatch注冊Notifier actor以接收Terminated消息。 Notifier將需要對DeathWatchProcessManager actor的DeathWatch ,並且一種方法是將對ProcessManager的引用作為消息發送(這是安全的,因為ActorRef是不可變的和可序列化的)。

class Notifier extends Actor {
  var processManager: Option[ActorRef] = None

  def receive: Receive = {
    case aRef: ActorRef =>
      if (processManager.isEmpty) {
        processManager = Some(aRef)
        context.watch(aRef) // register to "watch" the process manager
      }
    case Terminated =>
      // process manager was permanently stopped
    case ...
  }
}

object Demo extends App {
  val actorSystem = ActorSystem("my-actor-system")

  val notifier = actorSystem.actorOf(Props(classOf[Notifier]))
  val processManager = actorSystem.actorOf(Props(classOf[ProcessManager]))

  notifier ! processManager // send processManager's ref to the notifier
  ...
  processManager ! "some message which will fail and stop pm actor"
  ...
}

需要注意的是:在嘗試創建ProcessManager時拋出ActorInitializationException之前,可能無法執行DeathWatch注冊。


如果您需要在ProcessManager的子ProcessManager拋出異常時向Notifier發送消息,則在ProcessManager覆蓋Supervisor策略並將此消息作為策略的一部分發送。 就像是:

class ProcessManager extends Actor {
  import akka.actor.OneForOneStrategy
  import akka.actor.SupervisorStrategy._
  import scala.concurrent.duration._

  override val supervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
      case _: ActorInitializationException =>
        val notifier = context.actorSelection("/path/to/notifier")
        notifier ! CustomErrorMessage
        Stop
      case _: Exception => Escalate
   }

   def receive: Receive = {
     ...
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM