State is the information an actor uses to represent its current condition and decide what to do next. A wallet balance is state: an incoming command changes or reads that balance, and later commands see the resulting value. Keeping this information inside an actor makes concurrent state management sequential: the actor processes one message at a time. section 2.3
A small actor can carry state through its behavior. Its behavior receives the current total and a command, calculates a new total, and returns a new behavior configured with that total. This makes each accepted message transition explicit rather than sharing a mutable value across concurrent callers. section 2.3
Listing 2.5 Wallet actor with state
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
object WalletState {
sealed trait Command
final case class Increase(amount: Int) extends Command
final case class Decrease(amount: Int) extends Command
def apply(total: Int, max: Int): Behavior[Command] = #1
Behaviors.receive { (context, message) =>
message match {
case Increase(amount) =>
val current = total + amount
if (current <= max) {
context.log.info(s"increasing to $current")
apply(current, max) #2
} else {
context.log.info(
s"I'm overloaded. Counting '$current' while
max is '$max'. Stopping")
Behaviors.stopped #3
}
case Decrease(amount) => #4
...
}
}
}
The wallet behavior accepts Increase and Decrease commands, computes a current total, and recursively returns behavior for the next state. It stops when an update would exceed its configured limit. section 2.3
Model actor state around a clear protocol and its valid transitions:
- Represent requested actions as command types, such as Increase and Decrease, rather than relying on bare integers outside a minimal example. section 2.3
- Check a proposed update against business limits before adopting it; the example stops when its total would move beyond zero through two. section 2.3
- Keep current data in a State value when using event sourcing, then derive each next State from an event. section 9.2.1
- Use a unique persistence identity for durable entities; sharding can combine an entity type key and ID to avoid collisions across nodes. section 9.2.1
Wallet balance: from local state to durable state
A wallet starts at zero. AddFunds records an accepted addition; ReserveFunds succeeds only when the current balance covers the requested amount, otherwise it records a denial. The event handler turns FundsAdded into a larger balance, FundsReserved into a smaller one, and leaves the balance unchanged for FundsReservationDenied. This preserves the decision and the state transition separately, while persistence and snapshots make the balance durable across failures. section 12.1.1 section 12.1.1
State becomes more consequential when many wallets must be served. Sharding distributes entities by ID across nodes, while persistence, snapshot retention, and restart-with-backoff support a stateful wallet that can survive process failures. The business rule remains local: funds are granted only when available as the command is processed, avoiding race conditions over the balance. section 12.1.1






































