Custom supervisor strategies

The default strategy of restarting an actor on failure is not always what we want. In particular, for actors that carry a lot of data, we might want to resume processing after an exception rather than restarting the actor. Akka lets us customize this behavior by setting a supervisor strategy in the actor's supervisor.

Recall that all actors have parents, including the top-level actors, who are children of a special actor called the user guardian. By default, an actor's supervisor is his parent, and it is the supervisor who decides what happens to the actor on failure.

Thus, to change how an actor reacts to failure, you must set its parent's supervisor strategy. You do this by setting the supervisorStrategy attribute. The default strategy is equivalent to the following:

val supervisorStrategy = OneForOneStrategy() {
  case _:ActorInitializationException => Stop
  case _:ActorKilledException => Stop
  case _:DeathPactException => Stop
  case _:Exception => Restart
}

There are two components to a supervisor strategy:

  • OneForOneStrategy determines that the strategy applies only to the actor that failed. By contrast, we can use AllForOneStrategy, which applies the same strategy to all the supervisees. If a single child fails, all the children will be restarted (or stopped or resumed).
  • A partial function mapping Throwables to a Directive, which is an instruction on what to do in response to a failure. The default strategy, for instance, maps ActorInitializationException (which happens if the constructor fails) to the Stop directive and (almost all) other exceptions to Restart.

There are four directives:

  • Restart: This destroys the faulty actor and restarts it, binding the newborn actor to the old ActorRef. This clears the internal state of the actor, which may be a good thing (the actor might have failed because of some internal inconsistency).
  • Resume: The actor just moves on to processing the next message in its inbox.
  • Stop: The actor stops and is not restarted. This is useful in throwaway actors that you use to complete a single operation: if this operation fails, the actor is not needed any more.
  • Escalate: The supervisor itself rethrows the exception, hoping that its supervisor will know what to do with it.

A supervisor does not have access to which of its children failed. Thus, if an actor has children that might require different recovery strategies, it is best to create a set of intermediate supervisor actors to supervise the different groups of children.

As an example of setting the supervisor strategy, let's tweak the FetcherManager supervisor strategy to adopt an all-for-one strategy and stop its children when one of them fails. We start with the relevant imports:

import akka.actor.SupervisorStrategy._

Then, we just need to set the supervisorStrategy attribute in the FetcherManager definition:

class FetcherManager(...) extends Actor with ActorLogging {

  ...

  override val supervisorStrategy = AllForOneStrategy() {
    case _:ActorInitializationException => Stop
    case _:ActorKilledException => Stop
    case _:Exception => Stop
  }

  ...
}

If you run this through SBT, you will notice that when the code comes across the custom exception thrown by the response interpreter, the system halts. This is because all the actors apart from the fetcher manager are now defunct.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.106.237