liveBook · Manning

Finite-state machine

As explained in Akka in Action, Second Edition

A state machine is a computational model whose behavior depends on a finite or otherwise defined current state and its transitions.

A finite-state machine (FSM) models a component with a finite set of states. The same input can produce different results depending on the current state, also called its behavior. This is useful when an action is valid only at a particular point in a component’s lifecycle. Actors fit the model well: they process one message at a time and designate the behavior that will handle the next message. section 2.4 section 1.6.2

Wallet that can be turned on or off

A wallet starts activated with a total of zero. In the activated behavior, an Increase message adds to the total; Deactivate switches the wallet to its deactivated behavior; and another Activate changes nothing. In the deactivated behavior, Increase is discarded and reported without changing the total, Deactivate changes nothing, and Activate returns to the activated behavior while preserving the total. Thus the same Increase command succeeds in one state and has no effect in another. section 2.4

Listing 2.8 WalletOnOff actor
object WalletOnOff {
 
  sealed trait Command
  final case class Increase(amount: Int) extends Command
  final case object Deactivate extends Command
  final case object Activate extends Command
 
  def apply(): Behavior[Command] = activated(0)           #1
 
  def activated(total: Int): Behavior[Command] =          #2
    Behaviors.receive { (context, message) =>
      message match {
        case Increase(amount) =>
          val current = total + amount
          context.log.info(s"increasing to $current")
          resume(current)
        case Deactivate =>
          deactivated(total)
        case Activate =>
          Behaviors.same
      }
    }
 
  def deactivated(total: Int): Behavior[Command] = {      #3
    Behaviors.receive { (context, message) =>
      message match {
        case Increase =>
          context.log.info(s"wallet is deactivated. Can't increase")
          Behaviors.same
        case Deactivate =>
          Behaviors.same
        case Activate =>
          context.log.info(s"activating")
          activated(total)
      }
    }
}

The complete wallet actor places its command protocol beside the initial behavior and the two state-specific behavior functions. Each received command either returns the current behavior, switches to the other behavior, or returns a new activated behavior carrying an updated total. section 2.4

Implement an FSM with actor behaviors by following a small, explicit cycle:

  • Choose the initial state and any state value it carries, such as an activated wallet with total zero. section 2.4
  • Define one behavior for each state, handling the commands that can arrive in that state. section 2.4
  • For each command, keep the current behavior, return a behavior for the next state, or return a new behavior with updated state data. section 2.4
  • Treat the command protocol as the actor’s API: other actors communicate only by sending its messages. section 2.6

Closing a conversation

A conversation can begin in a started state that adds messages. Receiving CloseConversation moves it to a closed state. Messages sent after closure are ignored because the actor has swapped from the message-adding behavior to an ignoring behavior. This makes the lifecycle rule visible in the component’s message handling rather than leaving it implicit. section 1.6.2

An actor can also retain state as a value that is updated when messages arrive, but multiple behaviors provide the FSM form when different states must answer the same messages differently. Processing one message at a time lets each behavior focus on a single input and select the next behavior, avoiding an additional dimension of concurrency concerns. section 2.6 section 2.4

How Akka in Action, Second Edition covers it

How deep it goes
Defines FSMs and works through two wallet behaviors, their commands, state transitions, and observable output without formal detail.
Examples
Demonstrates an activated/deactivated wallet and a conversation that changes from started to closed.
What it assumes
Teaches FSM behavior changes from actor message handling rather than assuming prior state-machine or failure-handling experience.
What you can do after
Build it from scratch with actor behaviors that retain state, ignore invalid commands, and switch handling for later messages.
How it connects
Connects finite-state machines with actors, behaviors, message protocols, actor state, and concurrency handling.

Also explained in

Compare how 9 books explain finite-state machine →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Akka in Action, Second Edition. The section links point to the parts of the book it draws on.