Akka Supervisor Strategy - Correct Use Case
<p>I have been using Akka Supervisor Strategy to handle business logic exceptions.</p>

<p>Reading one of the most famous Scala blog series <a href="http://danielwestheide.com/blog/2013/03/20/the-neophytes-guide-to-scala-part-15-dealing-with-failure-in-actor-systems.html" rel="nofollow">Neophyte</a>, I found him giving a different purpose for what I have always been doing.</p>

<p>Example:</p>

<p>Let's say I have an HttpActor that should contact an external resource and in case it's down, I will throw an Exception, for now a <code>ResourceUnavailableException</code>.</p>

<p>In case my Supervisor catches that, I will call a Restart on my HttpActor, and in my HttpActor <code>preRestart</code> method, I will call do a <code>schedulerOnce</code> to retry that.</p>

<p>The actor:</p>

<pre><code>class HttpActor extends Actor with ActorLogging {

  implicit val system = context.system

  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    log.info(s"Restarting Actor due: ${reason.getCause}")
    message foreach { msg =&gt;
      context.system.scheduler.scheduleOnce(10.seconds, self, msg)
    }
  }

  def receive = LoggingReceive {

    case g: GetRequest =&gt;
      doRequest(http.doGet(g), g.httpManager.url, sender())
  }
</code></pre>

<p>A Supervisor:</p>

<pre><code>class HttpSupervisor extends Actor with ActorLogging with RouterHelper {

  override val supervisorStrategy =
    OneForOneStrategy(maxNrOfRetries = 5) {
      case _: ResourceUnavailableException   =&gt; Restart
      case _: Exception                      =&gt; Escalate
    }

  var router = makeRouter[HttpActor](5)

  def receive = LoggingReceive {
    case g: GetRequest =&gt;
      router.route(g, sender())

    case Terminated(a) =&gt;
      router = router.removeRoutee(a)
      val r = context.actorOf(Props[HttpActor])
      context watch r
      router = router.addRoutee(r)
  }
}
</code></pre>

<p>What's the point here?</p>

<p>In case my <code>doRequest</code> method throws the <code>ResourceUnavailableException</code>, the supervisor will get that and restart the actor, forcing it to resend the message after some time, according to the scheduler. The advantages I see is the fact I get for free the number of retries and a nice way to handle the exception itself.</p>

<p>Now looking at the blog, he shows a different approach in case you need a retry stuff, just sending messages like this:</p>

<pre><code>def receive = {
  case EspressoRequest =&gt;
    val receipt = register ? Transaction(Espresso)
    receipt.map((EspressoCup(Filled), _)).recover {
      case _: AskTimeoutException =&gt; ComebackLater
    } pipeTo(sender)

  case ClosingTime =&gt; context.system.shutdown()
}
</code></pre>

<p>Here in case of <code>AskTimeoutException</code> of the <code>Future</code>, he pipes the result as a <code>ComebackLater</code> object, which he will handle doing this:</p>

<pre><code>case ComebackLater =&gt;
      log.info("grumble, grumble")
      context.system.scheduler.scheduleOnce(300.millis) {
        coffeeSource ! EspressoRequest
      }
</code></pre>

<p>For me this is pretty much what you can do with the strategy supervisor, but in a manually way, with no built in number of retries logic.</p>

<p>So what is the best approach here and why? Is my concept of using akka supervisor strategy completely wrong?</p>