Achieve akka actor and his son regulation

akka, the father of actor can be defined supervisorStartegy abnormal regulation to implement the sub-actor coping strategies.

*   override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
*     case _: ArithmeticException      => Resume
*     case _: NullPointerException     => Restart
*     case _: IllegalArgumentException => Stop
*     case _: Exception                => Escalate
*   }

The above is a concrete realization of regulatory policy, you can see the specific abnormal coping strategies Resume, Restart, Stop and Escalate.

 

When the parent actor generating sub-actor, the abnormality information transmission will be recorded by the parent actor in the parent of the child actor.

 

The following are specific regulatory implementation.

Invoke the message processing sub-actor () function, the function will catch exceptions thrown in the receive (), and the function processed handleInvokeFailure ().

final def invoke(messageHandle: Envelope): Unit = {
  val influenceReceiveTimeout = !messageHandle.message.isInstanceOf[NotInfluenceReceiveTimeout]
  try {
    currentMessage = messageHandle
    if (influenceReceiveTimeout)
      cancelReceiveTimeout()
    messageHandle.message match {
      case _: AutoReceivedMessage => autoReceiveMessage(messageHandle)
      case msg                    => receiveMessage(msg)
    }
    currentMessage = null // reset current message after successful invocation
  } catch handleNonFatalOrInterruptedException { e =>
    handleInvokeFailure(Nil, e)
  } finally {
    // Schedule or reschedule receive timeout
    checkReceiveTimeout(reschedule = influenceReceiveTimeout)
  }
}

In handleInvokeFailure () function, an error message will be directly encapsulated into a message delivery system of the parent to the parent actor Failed message queue system type.

Parent actor will read time by reading the system message queue to abnormality occurs in the sub-actor.

In the systemInvoke to invokeAll () function will perform a specific process.

@tailrec
def invokeAll(messages: EarliestFirstSystemMessageList, currentState: Int): Unit = {
  val rest = messages.tail
  val message = messages.head
  message.unlink()
  try {
    message match {
      case message: SystemMessage if shouldStash(message, currentState) => stash(message)
      case f: Failed                                                    => handleFailure(f)
      case DeathWatchNotification(a, ec, at)                            => watchedActorTerminated(a, ec, at)
      case Create(failure)                                              => create(failure)
      case Watch(watchee, watcher)                                      => addWatcher(watchee, watcher)
      case Unwatch(watchee, watcher)                                    => remWatcher(watchee, watcher)
      case Recreate(cause)                                              => faultRecreate(cause)
      case Suspend()                                                    => faultSuspend()
      case Resume(inRespToFailure)                                      => faultResume(inRespToFailure)
      case Terminate()                                                  => terminate()
      case Supervise(child, async)                                      => supervise(child, async)
      case NoMessage                                                    => // only here to suppress warning
    }
  } catch handleNonFatalOrInterruptedException { e =>
    handleInvokeFailure(Nil, e)
  }
  val newState = calculateState
  // As each state accepts a strict subset of another state, it is enough to unstash if we "walk up" the state
  // chain
  val todo = if (newState < currentState) rest.reversePrepend(unstashAll()) else rest

  if (isTerminated) sendAllToDeadLetters(todo)
  else if (todo.nonEmpty) invokeAll(todo, newState)
}

Here, prior to encapsulation of Failed event will handleFailure () function corresponding processing.

In handleFailure () anomalies corresponding handler will be based on the regulatory strategy previously defined to be made here.

final protected def handleFailure(f: Failed): Unit = {
  currentMessage = Envelope(f, f.child, system)
  getChildByRef(f.child) match {
    /*
     * only act upon the failure, if it comes from a currently known child;
     * the UID protects against reception of a Failed from a child which was
     * killed in preRestart and re-created in postRestart
     */
    case Some(stats) if stats.uid == f.uid =>
      if (!actor.supervisorStrategy.handleFailure(this, f.child, f.cause, stats, getAllChildStats)) throw f.cause
    case Some(stats) =>
      publish(
        Debug(
          self.path.toString,
          clazz(actor),
          "dropping Failed(" + f.cause + ") from old child " + f.child + " (uid=" + stats.uid + " != " + f.uid + ")"))
    case None =>
      publish(
        Debug(self.path.toString, clazz(actor), "dropping Failed(" + f.cause + ") from unknown child " + f.child))
  }
}

Here, when the configuration is Escalate coping strategies when it will directly false, will lead directly to the exception thrown handled in a more higher-level actor.

Published 141 original articles · won praise 19 · Views 100,000 +

Guess you like

Origin blog.csdn.net/weixin_40318210/article/details/90737644
Recommended