# Actors with Apache Pekko and Akka — Scala

Source: https://www.geekswithgeeks.com/en/scala/k-actors

> Understand the actor model and when to use it.

## Message-driven concurrency

The **actor model** structures concurrent systems as **actors**: lightweight objects with private state that communicate only by **asynchronous messages**, processing one message at a time, so no locks are needed. Actors form **supervision hierarchies**: a parent decides whether to restart, resume or stop a failing child, which is the "let it crash" approach to resilience borrowed from Erlang. **Akka** popularised actors on the JVM, along with Akka Streams, clustering, sharding and persistence. In 2022, Akka moved to a source-available licence that requires a paid licence for many commercial uses, and the community created **Apache Pekko**, an Apache-licensed fork of Akka 2.6 with largely the same APIs under the `org.apache.pekko` package. **Typed actors** (`Behavior[Message]`) make the accepted messages part of the type. Use actors for stateful, long-lived entities (devices, sessions, game rooms, IoT), distributed systems with clustering and stream processing with backpressure. For simple request/response services, Futures or effect systems are usually simpler.

## A typed actor holding cart state (Pekko)

State changes by returning a new behaviour; other actors reply via ActorRef.

```scala
import org.apache.pekko.actor.typed.{ActorRef, ActorSystem, Behavior}
import org.apache.pekko.actor.typed.scaladsl.Behaviors

object Cart:
  sealed trait Command
  final case class AddItem(sku: String, qty: Int) extends Command
  final case class GetTotal(replyTo: ActorRef[Int]) extends Command

  def apply(items: Map[String, Int] = Map.empty): Behavior[Command] =
    Behaviors.receiveMessage {
      case AddItem(sku, qty) =>
        val updated = items.updated(sku, items.getOrElse(sku, 0) + qty)
        Cart(updated)                      // next behaviour carries the new state
      case GetTotal(replyTo) =>
        replyTo ! items.values.sum         // reply asynchronously
        Behaviors.same
    }

object Printer:
  def apply(): Behavior[Int] = Behaviors.receiveMessage { total =>
    println(s"items in cart: $total")
    Behaviors.same
  }

@main def cartDemo(): Unit =
  val system = ActorSystem(Behaviors.setup[Unit] { ctx =>
    val cart = ctx.spawn(Cart(), "cart-asha")
    val printer = ctx.spawn(Printer(), "printer")
    cart ! Cart.AddItem("pen", 2)
    cart ! Cart.AddItem("ink", 1)
    cart ! Cart.GetTotal(printer)          // printer eventually prints: items in cart: 3
    Behaviors.empty
  }, "shop")
```

## Check licences before choosing Akka

Since 2022, newer Akka versions are not under an open-source licence for most commercial production use. Many teams choose Apache Pekko for an Apache 2.0-licensed alternative with familiar APIs.

**Quiz:** How do actors avoid locks around their state?

- [x] Each actor processes one message at a time and its state is private, changed only by its own message handling
- [ ] They use synchronized blocks
- [ ] They never have state
- [ ] They use global variables

*Answer:* Each actor processes one message at a time and its state is private, changed only by its own message handling. Encapsulated state plus sequential message processing removes the need for locks.
