2017-07-20 3 views
1

Ich habe zwei Schauspieler:Akka: Wie kann ich das Scheitern eines Schauspielers in einem anderen (nicht kindlichen) Schauspieler feststellen?

Process die einige Prozesse im System behandelt (zB Anmeldung Benutzer, Einkauf, etc.)

Notifier - den Benutzer benachrichtigen soll, wenn ein Fehler in Process aufgetreten . Ich muss einen Fehler des ProcessManager-Aktors abfangen (er war fehlgeschlagen und wurde aus welchem ​​Grund auch immer gestoppt, z. B. weil ActorInitializationException oder max neustart time erreicht wurde und der Prozessmanager-Aktor gestoppt wurde).

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.")) 
     } 
    } 

Wie kann ich fangen Kündigung (wegen Fehler) von Process Schauspieler innen Notifier Schauspieler?

BEARBEITEN Lassen Sie mich den Kontext meines Problems erklären.

Ich bin PM-Schauspieler in Play-Controller erstellen und senden Sie die Nachricht an sie (Tell) und ich gebe Ok Antwort sofort an den Benutzer zurück. PM-Akteur erstellt einen anderen untergeordneten Akteur und während der Erstellung wird ActorInitializationException ausgelöst. Ich muss den Benutzer benachrichtigen (via Web-Socket, mit Notifier-Akteur), dass etwas schief gelaufen ist.

Antwort

3

können Sie DeathWatch verwenden, um die Notifier Schauspieler für den Empfang der Terminated Nachricht zu registrieren, wenn die ProcessManager Schauspieler dauerhaft anhalten. Notifier benötigen einen Verweis auf den ProcessManager Aktor für die DeathWatch, und eine Möglichkeit, das zu tun ist, senden Sie den Verweis auf ProcessManager als eine Nachricht (das ist sicher, weil ActorRef unveränderlich und serialisierbar ist).

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" 
    ... 
} 

Ein Nachteil: Es ist nicht möglich sein könnte, für die DeathWatch Registrierung geschehen, bevor ein ActorInitializationException ausgelöst wird, wenn die ProcessManager zu schaffen versucht.


Wenn Sie eine Nachricht an Notifier senden müssen, wenn ein Kind von ProcessManager eine Ausnahme auslöst, dann überschreiben die Supervisor-Strategie in ProcessManager und diese Nachricht als Teil der Strategie senden. Etwas wie:

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

lassen Sie mich den Kontext meines Problems erklären. Ich erstelle PM-Darsteller im Play-Controller und sende die Nachricht an ihn (Tell) und ich gebe Ok-Antwort sofort an den Benutzer zurück. PM-Akteur erstellt einen anderen untergeordneten Akteur und während der Erstellung wird ActorInitializationException ausgelöst. Ich muss den Benutzer benachrichtigen (via Web-Socket, mit Notifier-Akteur), dass etwas schief gelaufen ist. Diese Lösung löst dieses Problem nicht, aber danke. – Teimuraz

+0

@ moreo: Aktualisiert. – chunjef

Verwandte Themen