UP | HOME
../../

Akka Ops: Create, Send, Become, Supervise

Table of Contents

This is part of Akka Actors with Scala. Understanding all that is here is spiral-like. Do read these notes first. Secondly, TypeSafe Activator: Akka Get Started. Third, to better understand, read the details given in Akka Examples (perhaps skipping the Documentation).

1 Akka Actors

  1. Akka Actors: Extremely lightweight (> 2.7 million actors per GB RAM) import akka.actor._
  2. Messages are the "kinetic energy" in an actor system.
  3. Actors can have lots of buffered "potential energy", but cannot do anything with it until triggered by a message.
  4. Everything is asynchronous and lockless.

1.1 Example Actor

case class Greeting (who: String)

class GreetingActor extends Actor {
  def receive = {
    case Greeting(who) =>
      sender ! (s"Hello, $who! Thanks.")
  }
}

2 Akka Actors "Systems"

  1. Allocate (internal) threads: ActorSystem acsywsu = ActorSystem.create("WSU-CEG-7370-Actors");
  2. Allocate (internal) threads: ActorSystem acsyiiitd = ActorSystem.create("IIID-5xx-DIC-Actors");
  3. Several actor systems, possibly with different configurations, can co-exist.

    val grtr = acsyiiitd . actorOf(Props[GreetingActor], "greeter")
    grtr ! Greeting("Brad Pitt")
    
  4. Props is a configuration class to specify options for the creation of actors.
  5. Try the above in scala REPL. You need the import shown below.
  6. import akka.actor.{ ActorRef, ActorSystem, Props, Actor }
  7. glitch: akka://WSU-CEG-7370-Actors/deadLetters

3 An Actor in Java

  1. Akka actors are do-able in Java. Much longer.

    public class Greeting implements Serializable {
      public final String who;
      public Greeting(String who) {
        this.who = who;
      }
    }
    
  2. Continued …

3.1 An Actor in Java, contd-1

public class GreetingActor extends UntypedActor {
  LoggingAdapter log = Logging.getLogger(getContext().system(), this);
  public void onReceive(Object message) throws Exception {
    if (message instanceof Greeting)
      getSender.tell("Hello " + ((Greeting) message).who + " Thanks.");
  }
} 
  1. Continued …

3.2 An Actor in Java, contd-2

ActorSystem acsy = ActorSystem.create("WSU-CEG-7370-Actors");
ActorRef grtr = acsy . actorOf(
  new Props(GreetingActor.class), "greeter");
grtr.tell(new Greeting("Brad Pitt"));  

4 Create an Actor

  1. Create an actor by calling ActorContext.spawn(). The creator actor becomes the parent of the newly created child actor.
  2. Akka Actor receive message loop is exhaustive, different from Erlang and the late Scala "native" Actors.
  3. Provide a pattern match for all messages that the actor can accept.
  4. To handle unknown messages have a default case case _ => ...
  5. Killing an Actor: victim ! Kill
  6. context.system.shutdown() the ActorSystem when everything’s finished

5 Actor Lifecycle

fig-actor-lifecycle.png

Figure 1: Actor Lifecycle

6 Actor Op: Send

  1. The method named receive defines how messages are handled.
  2. The Bang ! aka tell.
  3. Asynchronous and Non-blocking – "Fire-forget"
  4. Order of send == order of arrival in the mailbox of receiving actor. Message ordering is guaranteed on a per-sender basis.
  5. The size of the mailbox can be bounded (cf Actor Std Model) or unbounded.
  6. def ! (message: Any)
    (implicit sender: ActorRef = Actor.noSender)
  7. The Query ? sends a message asynchronously and returns a Future representing a possible reply. Aka ask.

7 Actor Op: Become

  1. Behaviors can be pushed and popped
  2. context.become Replaces the current (the top of the behavior stack) behavior
  3. Will now react according to the new behavior to the messages
  4. context.unbecome pop the stack

7.1 Example: HotSwapActor

import akka.actor._
class HotSwapActor extends Actor {
  import context._
  def angry: Receive = {
    case "ang" => sender ! "I am already angry >:("
    case "hap" => become(happy)
  }

  def happy: Receive = {
    case "hap" => sender ! "I am already happy :-)"
    case "ang" => become(angry)
  }

  def receive = {
    case "ang" => become(angry)
    case "hap" => become(happy)
  }
}

7.2 Become – Why?

  1. Implement finite state machines import akka.actor.FSM
  2. Spawn up an empty generic worker actor that can become whatever the master needs
  3. Let a highly contended actor adaptively transform into an actor pool or a Router
  4. Implement graceful degradation

7.3 Finite State Machines, and P3

  1. http://www.typesafe.com/activator/template/akka-sample-fsm-scala
  2. ./dining-philosophers-akka-fsm.html
  3. IIITD DIC (WSU CEG 7370) P3: Understand the example above, and answer the questions.

7.4 Add to the Stack, Not Replace

import akka.event.Logging; import akka.actor._
case object Swap
class Swapper extends Actor {  import context._
  val log = Logging(system, this) 
  def receive = {
    case Swap =>
      log.info("Hi")
      become({
        case Swap =>
          log.info("Ho")
          unbecome() /* just for fun */
      }, discardOld = false) /* not replace */  }}

object SwapperApp extends App {
  val sys = ActorSystem("SwapperSystem")
  val a = sys.actorOf(Props[Swapper], name="swapper")
  // alternately logs Hi, Ho, ...
  a!Swap; a!Swap; a!Swap; a!Swap; a!Swap; a!Swap
}

8 Actor Op [Hidden]: Supervise

  1. "Let it crash!"
    1. When an actor crashes, its parent can either restart, stop it, or escalate the failure, up the hierarchy of actors.
    2. A chain of responsibility, all the way to the top.
  2. Every single Akka actor has a default supervisor strategy. Which is usually sufficient. But it can be overridden.
  3. Provides clean separation of business logic and error handling
  4. Traditional failure management:
    1. You are given a single thread of control
    2. Need to do all explicit error handling WITHIN this single thread
    3. Errors do not propagate between threads
    4. Leads to defensive programming, with error handling tangled with business logic

9 DeathWatch

  1. Register to receive Terminated message provided by the DeathWatch component of the Akka actor system.

    import akka.actor.{ Actor, Props, Terminated }
    class WatchActor extends Actor {
      val child = context.actorOf(Props.empty, "child")
      context.watch(child)   // registration
      var lastSender = system.deadLetters
      def receive = {
        case "kill" =>
          context.stop(child); lastSender = sender()
        case Terminated(`child`) =>
          lastSender ! "finished"
      }
    }
    
  2. Note the back-quotes in Terminated(`child`)

10 References

  1. Akka Documentation https://doc.akka.io/docs/akka/current/ Nearly all the code snippets and figures are from here. Reference.
  2. Jonas Boner, "Above the Clouds: Introducing Akka", 2011. Web search. Video or pdf. Highly recommended.

11 End


Copyright © 2020 www.wright.edu/~pmateti • 2020-01-31