我有两个演员:
ProcessManager 处理系统中的某些进程(例如,用户注册,购买等)
通知程序 - 如果ProcessManager中发生了某些错误,则应通知用户。 我需要捕获ProcessManager actor的失败(它失败并因任何原因而停止,例如,由于ActorInitializationException或达到最大重启时间并且Process manager 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."))
}
}
如何在通知程序演员中捕获 ProcessManager 演员的终止(因为失败)?
修改 让我解释一下我的问题的背景。
我正在Play控制器中创建PM actor并将消息发送给它(Tell),我立即向用户返回Ok响应。 PM actor创建另一个子actor,在创建过程中抛出ActorInitializationException。我需要通知用户(通过Web套接字,使用Notifier actor),出现问题。
答案 0 :(得分:3)
当Notifier
演员永久停止时,您可以使用DeathWatch
注册Terminated
演员以接收ProcessManager
讯息。 Notifier
需要ProcessManager
DeathWatch
的{{1}} actor的引用,一种方法是将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"
...
}
有一点需要注意:DeathWatch
注册可能无法在尝试创建ActorInitializationException
时引发ProcessManager
之前发生。
如果您需要在Notifier
的孩子抛出异常时向ProcessManager
发送消息,请覆盖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 = {
...
}
}