igx igx - 1 month ago 10
Scala Question

can akka actor capture a specific message in all states without implementing the same code

I have an actor that manages different states e.g:

case object Start
case object Stop
case object Init

class Foo extends Actor {

def receive: Receive = {
case Init =>
doSomeInit()
context become busy
self ! Start
case Stop =>
context stop self

}
}
def busy: Receive = {
case Start =>
doingSomeProcessing()
context become receive
case Stop =>
context stop self
}
}


I want to avoid writing the Stop handling code in every state (similar to whenUnhandled in FSM )
is there idiomatic way to do that without using FSM ?

Answer

Use orElse and move the common messages to separate partial function. receive and busy are partial functions. You can compose partial functions using orElse as shown in the code below.

Order is important. So based on the use case do f1 orElse f2 or f2 orElse f1 f1, f2 are partial functions

case object Start
  case object Stop
  case object Init

  class Foo extends Actor {

    def common: Receive = {
      case Stop =>
        context stop self
    }

    def receive: Receive = common orElse {
      case Init =>
        context become busy
        self ! Start
    }

    def busy: Receive = common orElse {
      case Start =>
        context become receive
    }
  }

Scala REPL

scala> val f: PartialFunction[Int, String] = { case 1 => "one"}
f: PartialFunction[Int, String] = <function1>
scala> val g: PartialFunction[Int, String] = { case 2 => "two"}
g: PartialFunction[Int, String] = <function1>
scala> val x = f orElse g
scala> f(1)
res9: String = "one"
scala> x(2)
res10: String = "two"
scala> x(1)
res11: String = "one"
Comments