An actor behavior defines how an actor handles one incoming message and selects what will handle the next one. This keeps processing sequential inside the actor: focus on one message at a time rather than coordinating shared mutable state. A behavior may remain unchanged, transition to another behavior, or stop the actor. section 1.6.2 section 2.6
Receive a message and keep the same behavior
A typed wallet can use Behavior[Int] with Behaviors.receive. The receive function gets an ActorContext and a message, logs the deposited amount, and returns Behaviors.same. Returning the same behavior means the next message is handled in the same way. section 2.2.4
Behaviors can also carry state through function parameters. A wallet behavior receiving Increase computes a new total and returns a fresh behavior such as apply(current, max). If the total exceeds its limit, it returns Behaviors.stopped instead. This represents state message by message without exposing it to other actors. section 2.3
Use distinct behaviors when state changes the meaning of the same message, not merely a stored value. An activated wallet accepts Increase and returns its activated behavior with an updated total. A deactivated wallet discards Increase, remains deactivated, and switches back only after Activate. Such behavior states form a finite state machine. 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)
}
}
}
Compare the command protocol with the activated and deactivated handlers to see each message’s behavior transition. section 2.4
When defining the next behavior, choose the result that matches the actor’s state transition:
- Return Behaviors.same when the current handler should continue unchanged. section 2.2.4
- Return another behavior function when a message changes how later messages are interpreted. section 2.4
- Return Behaviors.stopped when processing detects an unacceptable state. section 2.3
