Supervisor

Handling errors and supervising child actors are core functionalities of the Akka Actor model. The supervision strategy allows a parent actor to decide how to handle errors thrown by its children, making the system more resilient. Let's dive into how you can implement a parent actor and manage error handling in an Akka system.

Understanding Supervision Strategies

In Akka, when an actor throws an exception, it's suspended and the supervision strategy of its parent actor is invoked. The parent can decide to: - Resume the child actor, keeping its internal state. - Restart the child actor, resetting its internal state. - Stop the child actor permanently. - Escalate the failure, causing the parent itself to stop and be supervised by its own parent.

Step 1: Setting Up Your Project

First, ensure your build.sbt file includes dependencies for Akka Typed:

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor-typed" % "2.6.15"
)

Step 2: Defining the Child Actor

Create a simple child actor that can throw an exception based on a received message. This example defines a Worker actor that supports DoWork and Fail messages:

import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.Behavior

object Worker {
  sealed trait Command
  case object DoWork extends Command
  case object Fail extends Command

  def apply(): Behavior[Command] = Behaviors.receiveMessage {
    case DoWork =>
      println("Worker is doing work")
      Behaviors.same
    case Fail =>
      throw new RuntimeException("Worker failed")
  }
}

Step 3: Creating the Parent Actor with Supervision Strategy

Define a parent actor that creates the Worker actor and specifies a supervision strategy for it. This example uses a supervision strategy to restart the child actor upon failure:

import akka.actor.typed.ActorSystem
import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.Behaviors

object Supervisor {
  def apply(): Behavior[Worker.Command] = Behaviors
    .supervise[Worker.Command] {
      Behaviors.setup { context =>
        val worker = context.spawn(Worker(), "workerActor")

        // Example: sending messages to the worker
        worker ! Worker.DoWork
        worker ! Worker.Fail // This will cause the worker to throw an exception

        Behaviors.receiveMessage { message =>
          worker ! message
          Behaviors.same
        }
      }
    }
    .onFailure[Exception](SupervisorStrategy.restart) // Supervision strategy to restart the child
}

Step 4: Running the System

Create and run an ActorSystem with the Supervisor actor:

object Main extends App {
  val system: ActorSystem[Worker.Command] = ActorSystem(Supervisor(), "supervisorSystem")

  // Optionally, interact with the system
  // e.g., system ! Worker.DoWork
}

Observing Behavior

When the Worker actor throws an exception due to the Fail message: - The parent's supervision strategy is invoked. - The strategy decides to restart the Worker actor. - The Worker actor's state is reset, and it's ready to receive messages again.

Conclusion

This tutorial introduced the basics of actor supervision in Akka. Supervision strategies empower you to build resilient systems by effectively managing failures. Experimenting with different strategies and understanding their impact on actor states is crucial for leveraging Akka's full potential for building fault-tolerant systems.