Search code examples
javaexceptionakkaakka-supervision

Relationship of Akka SupervisorStrategies to children


Java API here. I am trying to understand how Akka actor supervision really works, specifically supervisor strategies. To me, the strategy feels like its just (essentially) a mapping of exceptions to directives.

I just read the official Akka Fault Tolerance documentation, but nowhere in that doc do they actually, explicitly state when/where/how supervision strategies are triggered.

So I ask: when are supervision strategies engaged? When the child actor throws a Throwable from inside its onReceive method? Or something different?


Solution

  • You are correct except it includes throwables, that is Error, as well as Exception, in a default decider rule and it operates any time an Actor throws a Throwable. According to http://doc.akka.io/docs/akka/2.0/java/fault-tolerance.html#default-supervisor-strategy, by default if there is no defined supervisor strategy or it does not cover an exception thrown by a (user created) Actor, the following rules are executed in order until one is triggered:

    1. an ActorInitializationException will stop the failing child actor
    2. an ActorKilledException will stop the failing child actor
    3. other Exceptions will restart the failing child actor
    4. other types of Throwable will be escalated to parent actor

    An ok review of supervision is at http://doc.akka.io/docs/akka/2.3.11/general/supervision.html if you have not already seen it.

    A good discussion of it at the code level is in "Akka Concurrency" chapter 8 by Derek Wyatt. It mostly treats the Scala version, but I believe that Actor fault handling is implemented in Scala (with dependencies on Java).

    Looking in the 2.3.11 sources, the default Actor fault handling decider is in akka-actor_2.11-2.3.11-sources.jar\akka\actor.FaultHandling.scala and is:

    /**
       * When supervisorStrategy is not specified for an actor this
     * [[Decider]] is used by default in the supervisor strategy.
     * The child will be stopped when [[akka.actor.ActorInitializationException]],
     * [[akka.actor.ActorKilledException]], or [[akka.actor.DeathPactException]] is
     * thrown. It will be restarted for other `Exception` types.
     * The error is escalated if it's a `Throwable`, i.e. `Error`.
     */
    final val defaultDecider: Decider = {
      case _: ActorInitializationException ⇒ Stop
      case _: ActorKilledException         ⇒ Stop
      case _: DeathPactException           ⇒ Stop
      case _: Exception                    ⇒ Restart
    }
    
    /**
     * When supervisorStrategy is not specified for an actor this
     * is used by default. OneForOneStrategy with decider defined in
     * [[#defaultDecider]].
     */
    final val defaultStrategy: SupervisorStrategy = {
      OneForOneStrategy()(defaultDecider)
    }
    

    This agrees with the documentation - more and less insofar as defaultDecider does not include an explicit

    case _ => Escalate // _ is the scala wildcard for anything
    

    which is implemented in makeDecider functions that default to Escalate if a Throwable is not matched by defaultDecider; and the documentation does not mention inclusion of a provision for DeathPactException probably to reduce confusion with a detail.