Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to compose FSMs in Akka?

Tags:

scala

akka

fsm

For regular actors, they can be composed. But, I can't seem to find anything about doing it with FSMs. And there isn't a receive block to use += to add things to. Does anyone have any experience trying to generalize an FSM?

I can't provide a code example, because I don't have any code yet because I don't know if I can compose FSMs.

like image 422
Dante Romero Avatar asked Nov 01 '22 11:11

Dante Romero


1 Answers

You can compose state behaviour using partial functions in the same way that you compose Actor partial functions. The when() function requires a partial function of type scala.PartialFunction[FSM.this.Event, FSM.this.State]). In the example below, I extend the state Jibber with a partial function (e.g. some common behaviour) declared in the trait. You can use exactly the same technique to extend the onTermination behaviour from a trait using a PF declared as scala.PartialFunction[StopEvent, Unit].

I have lifted significant common behaviour out of some complex FSMs using this technique.

package monster

import akka.actor._
import monster.FlyingSpaghetti._

// State and data objects
object FlyingSpaghetti {

  trait State

  object Jibber extends State
  object Jabber extends State

  object Ping
  object Done

}

// Trait with common behaviour behaviour
trait FlyingSpaghetti  extends Actor with FSM[State,String]{
  val layer: StateFunction = {
    case Event(Done,s) ⇒
      println("Done behaviour layered")
      stop()
  }
}

class Monster() extends FlyingSpaghetti {

  startWith(Jibber,"jabber")
  self ! Ping
  println("Starting")

  // First, do the common behaviour PF then do specialised behaviour
  when(Jibber) (layer orElse {
    case Event(Ping,"jabber") ⇒
      println("jabber")
      goto(Jabber) using "jibber"
    case Event(Done,s) ⇒
      println("Done jabbering")
      stop()
  })

  when(Jabber) {
    case Event(Ping,"jibber") ⇒
      println("jibber")
      goto(Jibber) using "jabber"
    case Event(Done,s) ⇒
      println("Done jibbering")
      stop()
  }
}

object Run extends App {
  val system = ActorSystem("mySystem")
  val rattle = system.actorOf(Props[Monster])
  rattle ! Ping
  rattle ! Ping
  rattle ! Done
  Thread.sleep(100)
  system.shutdown()
}
like image 70
David Weber Avatar answered Nov 14 '22 23:11

David Weber