1

I am using Akka and would like to run some code for all cases of a PartialFunction. For actor supervision, I have something like:

val supervisorStrategy = OneForOneStrategy() {
  case npe: NullPointerException => Stop
  case re: RuntimeException => Restart
}

The only way I have found to run some code for all cases without having to write it again at every case, is:

val pf = new PartialFunction[Throwable, Directive] {
  def apply(throwable: Throwable) = {
    doSomething(throwable)
    throwable match {
      case NullPointerException => Stop
      case RuntimeException => Restart
    }
  }

  def isDefinedAt(throwable: Throwable) = true
}

val supervisorStrategy = OneForOneStrategy()(pf)

I have looked around and to other answers (like this one) but couldn't figure out any alternative way to the one I came up with.

Community
  • 1
  • 1
ticofab
  • 7,551
  • 13
  • 49
  • 90
  • Do you want `doSomething` to be called even if an exception which is neither `NullPointerException` nor `RuntimeException` is passed? – Alexey Romanov Nov 10 '16 at 16:58

3 Answers3

1

This should do it :

val supervisorStrategy = OneForOneStrategy() { 
 case x =>
  doSomething(x)
  x match {
    case npe: NullPointerException => Stop
    case re: RuntimeException => Restart
  }
}
C4stor
  • 8,355
  • 6
  • 29
  • 47
  • I had tried it but it doesn't compile: "Missing parameter type: x" – ticofab Nov 11 '16 at 07:15
  • it seems to work if I specify both the type of x and the actual function signature:def pf3: PartialFunction[Throwable, Directive] and (x: Throwable) – ticofab Nov 11 '16 at 07:25
  • Hey, I'm ever so sorry, my answer was wrong. I edited it : `x =>` became `case x =>` – C4stor Nov 15 '16 at 13:38
  • Thanks for updating! It still complains that the parameter is unknown, and even using `case x: Throwable => ... ` won't work... – ticofab Nov 15 '16 at 14:12
  • I don't really know at this point. Can you confirm you're using { and not ( to wrap the partial function ? – C4stor Nov 15 '16 at 15:03
1

Doesn't seem Akka-specific. You can always combine any two functions using andThen. Specifically:

package com.example

import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.{Decider, Restart, Stop}

object Answer extends App {
  val doSomething:PartialFunction[Throwable, Throwable] = { case e =>
    println(s"doing something with $e")
    e
  }

  val decide:Decider = {
    case _:NullPointerException => Stop
    case _:RuntimeException => Restart
  }

  val strategy = OneForOneStrategy()(doSomething andThen decide)

  val errors = Seq(new NullPointerException, new RuntimeException)
  errors map strategy.decider foreach println
}

More generally:

package com.example

object Answer extends App {
  val inspect:PartialFunction[Throwable, Throwable] = { case e =>
      println(s"inspecting $e")
      e
  }

  val decide:PartialFunction[Throwable, String] = {
    case npe:NullPointerException => "NPE!"
    case iae:IllegalArgumentException => "Bad arg!"
  }

  val combined = inspect andThen decide

  val errors = Seq(new NullPointerException, new IllegalArgumentException)
  errors map combined foreach println
}
Andrey
  • 8,882
  • 10
  • 58
  • 82
0

Thanks for the other answers, but in this Akka specific situation I can't get them to work. For instance, this won't compile:

val ft = OneForOneStrategy() { x: Throwable =>
  doSomething(x)
  x match {
    case npe: NullPointerException => Stop
    case re: RuntimeException => Stop
  }
}

Error:(48, 47) type mismatch;
found   : Throwable => akka.actor.SupervisorStrategy.Directive
required: akka.actor.SupervisorStrategy.Decider (which expands to) PartialFunction[Throwable,akka.actor.SupervisorStrategy.Directive]

I am using Akka 2.4.11 and Scala 2.11.8

The only working solution for me was the way I described in the initial question.

ticofab
  • 7,551
  • 13
  • 49
  • 90