scalaadvanced

Akka Actor System Basics

Build concurrent applications with Akka actors: message passing, behavior switching, and supervision.

scala
import akka.actor.typed.{ActorRef, ActorSystem, Behavior}
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}

// Message protocol
object Counter:
  sealed trait Command
  case object Increment extends Command
  case object Decrement extends Command
  case class GetCount(replyTo: ActorRef[Int]) extends Command
  case object Reset extends Command

  def apply(): Behavior[Command] =
    Behaviors.setup(ctx => new Counter(ctx))

class Counter(ctx: ActorContext[Counter.Command])
    extends AbstractBehavior[Counter.Command](ctx):
  import Counter.*
  private var count = 0

  override def onMessage(msg: Command): Behavior[Command] = msg match
    case Increment =>
      count += 1
      ctx.log.info(s"Incremented to $count")
      this
    case Decrement =>
      count -= 1
      ctx.log.info(s"Decremented to $count")
      this
    case GetCount(replyTo) =>
      replyTo ! count
      this
    case Reset =>
      count = 0
      ctx.log.info("Reset")
      this

// Functional style actor
object Greeter:
  sealed trait Command
  case class Greet(name: String, replyTo: ActorRef[String]) extends Command

  def apply(): Behavior[Command] =
    Behaviors.receive { (ctx, msg) =>
      msg match
        case Greet(name, replyTo) =>
          ctx.log.info(s"Greeting $name")
          replyTo ! s"Hello, $name!"
          Behaviors.same
    }

// Stateful actor with behavior switching
object Switch:
  sealed trait Command
  case object Toggle extends Command
  case class GetState(replyTo: ActorRef[String]) extends Command

  def apply(): Behavior[Command] = off()

  private def on(): Behavior[Command] =
    Behaviors.receive { (ctx, msg) =>
      msg match
        case Toggle =>
          ctx.log.info("Switching OFF")
          off()
        case GetState(replyTo) =>
          replyTo ! "ON"
          Behaviors.same
    }

  private def off(): Behavior[Command] =
    Behaviors.receive { (ctx, msg) =>
      msg match
        case Toggle =>
          ctx.log.info("Switching ON")
          on()
        case GetState(replyTo) =>
          replyTo ! "OFF"
          Behaviors.same
    }

// Guardian actor
object Guardian:
  def apply(): Behavior[Nothing] =
    Behaviors.setup[Nothing] { ctx =>
      val counter = ctx.spawn(Counter(), "counter")
      counter ! Counter.Increment
      counter ! Counter.Increment
      counter ! Counter.Increment

      val switch = ctx.spawn(Switch(), "switch")
      switch ! Switch.Toggle
      switch ! Switch.Toggle

      Behaviors.empty
    }

@main def run(): Unit =
  val system = ActorSystem(Guardian(), "demo")
  Thread.sleep(1000)
  system.terminate()

Use Cases

  • Concurrent message-passing systems
  • Stateful service actors
  • Behavior switching for state machines

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.