【问题标题】:Akka: how can I catch failure of one actor inside another (non child) actor?Akka:我怎样才能在另一个(非儿童)演员中发现一个演员的失败?
【发布时间】:2017-07-20 22:08:35
【问题描述】:

我有两个演员:

ProcessManager处理系统中的一些流程(例如,用户注册、购买等)

Notifier - 如果 ProcessManager 发生错误,应该通知用户。 我需要捕捉 ProcessManager 参与者的失败(它失败并因任何原因停止,例如,由于 ActorInitializationException 或达到最大重启时间并且流程管理器参与者已停止)。

   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 演员中捕获 ProcessManager 演员的终止(由于失败)?

编辑 让我解释一下我的问题的背景。

我正在 Play 控制器中创建 PM 演员并向其发送消息 (Tell),然后我立即向用户返回 Ok 响应。 PM actor 创建另一个子 actor,在创建过程中,会抛出 ActorInitializationException。我需要通知用户(通过 Web 套接字,使用 Notifier Actor)出现问题。

【问题讨论】:

    标签: exception akka akka-supervision


    【解决方案1】:

    ProcessManager 演员永久停止时,您可以使用DeathWatch 注册Notifier 演员以接收Terminated 消息。 Notifier 需要为DeathWatch 提供对ProcessManager 演员的引用,一种方法是将对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 时,DeathWatch 注册可能无法在 ActorInitializationException 被抛出之前发生。


    如果您需要在ProcessManager 的子级抛出异常时向Notifier 发送消息,则覆盖ProcessManager 中的主管策略并将此消息作为策略的一部分发送。比如:

    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 = {
         ...
       }
    }
    

    【讨论】:

    • 让我解释一下我的问题的背景。我在 Play 控制器中创建 PM actor 并将消息发送给它(告诉),然后我立即向用户返回 Ok 响应。 PM actor 创建另一个子 actor,在创建过程中,会抛出 ActorInitializationException。我需要通知用户(通过 Web 套接字,使用 Notifier Actor)出现问题。所以这个解决方案不能解决这个问题,但是谢谢。
    • @moreo:已更新。
    猜你喜欢
    • 1970-01-01
    • 2015-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多