no API for the remoting layer of Akka: it is purely driven by configuration.

Scaling Up : using multiple cores on one machine Scaling Out: distributing over a network

Good link

http://doc.akka.io/docs/akka/snapshot/scala/actors.html

Commands are ‘do stuff’ Events are ‘things have happened’

Notes from

http://doc.akka.io/docs/akka/2.3.14/AkkaScala.pdf?_ga=1.81147863.1792917576.1442301370

And now for the notes

Actors, form a hierarchy, escalate trouble to their parents.

Actors should not block

Actors are containers for behaviour and state - do not send behaviour within messages.

Actors should not mutate their state in the handlers of calls to other futures or actors - send a message back to yourself to avoid any risk of having several threads mutating your state.

Top-level actors are innermost part of your Error Kernal - so create them sparingly and prefer truly hierarchical. Reduces load on guardian actor which is the single point of contention.

…the most important aspect is that it is not possible to look inside an actor and get hold of its state from the outside.

each actor has exactly one mailbox to which all senders enqueue their messages…, there is no scanning the mailbox for the next matching one.

Actors can be Supervisors of children - starting and stopping then are reflected in the context immediately (even tho actually async)

Once an actor terminates, i.e. fails in a way which is not handled by a restart, stops itself or is stopped by its supervisor, it will free up its resources, draining all remaining messages from its mailbox into the system’s “dead letter mailbox” which will forward them to the EventStream as DeadLetters.

System has at least 3 actors:

  • /user: The Guardian Actor Actors created using system.actorOf() are children of this actor
  • /system: The System Guardian Used for orderly shutdown - ie it keeps logging going etc while the thing terminates
  • /: The Root Guardian Deals with top level actors...terminates children upon any type of exception

Lifecycle monitoring - called Deathwatch

When actor dies, all its kids are stopped and then lifecycle hooks are called to start it up again, ie preRestart, postRestart (which calls preStart)

An actor can listen to another actor, but only telling when it stops using the Terminated message. Use ActorContext.watch(targetActorRef) and ActorContext.unwatch(targetActorRef).

Supervisors default to OneForOneStrategy (ie one kid dies, and you can restart it) but can have AllForOneStrategy (if 1 kid dies, all kids are killed and restarted)

ActorPath, Logical defines functional location, config based remote deploy can move it.

You can create a path even if there is no actor there. Ie path has no lifecycle

"akka://my-sys/user/service-a/worker1" // purely local
"akka.tcp://my-sys@host.example.com:5678/user/service-b" // remote

ActorRef

Used to send messages to an actor. ActorCell holds the context Actor ie the class

Eg Actor.context.self.path

Actor.context.parent gives you the parent ActorRef Actor.context.children gives you the kids

Actors can mixin the Router trait.

akka.pattern.ask creates PromiseActorRef DeadLetterActorRef EmptyLocalActorRef

Creating

ActorSystem.actorOf and then ActorContext.actorOf to spawn the actor tree.

“/user” is the guardian actor for all user-created top-level actors; actors created using ActorSystem.actorOf are found below this one.

Finding

The actorRef can be found using ActorSystem.actorSelection.

Or, from an actor you can use the context and relative path

context.actorSelection("../brother") ! msg
context.actorSelection("/user/serviceA") ! msg // absolute path

You can wild card as in linux and then message them - eg send to all siblings and me.

context.actorSelection(“../*”) ! msg

Scaling

If you have an actor which you want to run many instances in parallel, declare it as withRouter. Then in config you can say how many, and where (eg remote).  Ie it creates a Router actor instead, which then spins up the actual Actors.

Messaging

the tell or ! method, which also underlies the ask pattern

At-most-once, message ordering per sender-receiver pair

• ! means “fire-and-forget”, e.g. send a message asynchronously and return immediately. Also known as tell. • ? sends a message asynchronously and returns a Future representing a possible reply. Also known as ask.

Ie Akka does not guarantee delivery!! Sending can fail even in local JVM due to StackOverflowError, OutOfMemoryError, mailbox full receiver is terminated.

Sender is not informed of a send fail, the supervisor is.

Background notes:

  • At-most-once is fastest, ie message may not arrive. Fire and forget
  • At-least-once, messages may be duplicated but not lost.
  • Exactly-once, slowest - state held at sending and receiving ends, with acks sent

Config

the default is to parse all application.conf, application.json and application.properties found at the root of the class path

Eg of custom application.conf

# In this file you can override any option defined in the reference files.
   # Copy in parts of the reference files and modify as you please.
akka {
   # Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
   # to STDOUT)
   loggers = ["akka.event.slf4j.Slf4jLogger"]
   # Log level used by the configured loggers (see "loggers") as soon
   # as they have been started; before that, see "stdout-loglevel"
   # Options: OFF, ERROR, WARNING, INFO, DEBUG loglevel = "DEBUG"
   # Log level for the very basic logger activated during ActorSystem startup.
   # This logger prints the log messages to stdout (System.out).
   # Options: OFF, ERROR, WARNING, INFO, DEBUG
   stdout-loglevel = "DEBUG"
   actor { 
      provider = "akka.cluster.ClusterActorRefProvider" 
      default-dispatcher { 
         # Throughput for default Dispatcher, set to 1 for as fair as possible 
         throughput = 10 
      }
   }
   remote { 
      # The port clients should connect to. Default is 2552. 
      netty.tcp.port = 4711 
   }
}

Actor

import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging 

class MyActor extends Actor {
 val log = Logging(context.system, this)
 def receive = {
 case "test" => log.info("received test")
 case _ => log.info("received unknown message")
 }
}

It is a good idea to provide factory methods on the companion object of each Actor which help keeping the creation of suitable Props as close to the actor definition as possible. This also avoids the pitfalls associated with using the Props.apply(…) method which takes a by-name argument, since within a companion object the given code block will not retain a reference to its enclosing scope:

object DemoActor {
  /**
   * Create Props for an actor of this type.
   * @param magciNumber The magic number to be passed to this actor’s constructor.
   * @return a Props for creating this actor, which can then be further configured
   * (e.g. calling `.withDispatcher()` on it)
   */
  def props(magicNumber: Int): Props = Props(new DemoActor(magicNumber))
  // Define all of your messages here.
  case object Initialise
  case class PingMessage(text:String)
} 

class DemoActor(magicNumber: Int) extends Actor {
 def receive = {
   case Initialise => log.info("Initialise received")
   case PingMessage(x) => sender() ! (x + magicNumber)
 }
} 

class SomeOtherActor extends Actor {
  val log = Logging(context.system, this);

 // Props(new DemoActor(42)) would not be safe
 context.actorOf(DemoActor.props(42), "demo")
 // ...
}

// To start it all up, eg in some other file
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.event.{LogSource, Logging}
import akka.http.scaladsl.model._
class FireStorm  extends App {
  implicit val system = ActorSystem("fireadmiral-system")
  implicit val materializer = ActorMaterializer()
  val authenticationActor = system.actorOf(AuthenticationActor.props())
  ...
}

Boostrap only one ActorSystem per system

import akka.actor.ActorSystem 

// ActorSystem is a heavy object: create only one per application
val system = ActorSystem("mySystem")
val myActor = system.actorOf(Props[MyActor], "myactor2") 

class FirstActor extends Actor {
  val child = context.actorOf(Props[MyActor], name = "myChild")
  // plus some behavior ...
}

Async with Futures

import akka.pattern.{ ask, pipe }
import system.dispatcher // The ExecutionContext that will be used
case class Result(x: Int, s: String, d: Double)
case object Request

implicit val timeout = Timeout(5 seconds) // needed for `?` below

val f: Future[Result] =
 for {
   x <- ask(actorA, Request).mapTo[Int] // call pattern directly
   s <- (actorB ask Request).mapTo[String] // call by implicit conversion 
   d <- (actorC ? Request).mapTo[Double] // call by symbolic name
 } yield Result(x, s, d) 
f pipeTo actorD // .. or .. 
pipe(f) to actorD

This example demonstrates ask together with the pipeTo pattern on futures, because this is likely to be a common combination

ASK - cant find it

Ask is not a method, but its a pattern which means you have to import it.

import akka.pattern.{ ask, pipe }

State machines

Become and unbecome can switch the receive function which is called by an actor when it gets a message.

============================================

One ActorSystem can collaborate with another using “Remoting”

A single ActorSystem can span JVMs if you use “Clustering”

Your top level actor should be a ‘processorsManager’. It only creates individual process managers, it doesn’t handle failure itself, but

Its kids can look after their own process - failures as well

The other top level actor is the ‘domainModel’ which looks after any actors responsible for data/domain info

To get ‘at-least-once’ delivery, need to look at Message Store, Guaranteed Delivery, Transactional Actor, Idempotent Receiver.

Key APIS:

  • actorOf(Props[ProcessManagers], "processManagers") Create actor
  • actorSelection("/users/*") Multi selection of actors
  • awaitTermination After using shutdown() you wait for it to stop
  • deadLetters This answers the ActorRef of the Dead Letter Channel
  • eventStream This answers the systems primary EventBus
  • isTerminated True if the system is fully stopped after a shutdown()
  • log Get LoggingAdapter for the system default logging to the eventStream
  • name The String name of the system
  • scheduler The systems scheduler to create timer events
  • shutdown() Stops the user guardian, which recusively stops all user children, then stops the system guardian and all system level actors, and finally terminates the system
  • stop(actor: ActorRef) Asynch stop the actor referenced. Sends a message to the user guardian and then waits for a reply - ie its asynch but does block.

At the least an actor must:

import akka.actor._
class ShoppingCart extends Actor
 def receive = {
   case _ =>
 }
}

GOTCHA

‘close over’ means that a closure can be created. So, if you reference sender within a closure you can be screwed:

context.system.scheduleOnce(1 minute) {
   sender ! Amessage()
}

Is bad as sender can have been replaced. So instead take a local reference prior to the closure being created

mySender = sender
context.system.scheduleOnce(1 minute) {
  mySender ! Amessage()
}

Failure handling:

Parent actors havea default supervisor strategy which has the following policies:

  • ActorInitializationException The failed child will be stopped
  • ActorKilledException Child will be stopped
  • Exception The child will be restarted
  • Throwable All other Throwable types are escallated to the parent.

Comms

You can use proto buffs or kryo for serialisation, default is java serialisation,  so you must configure proto..

Akka knows which actors are local and so will use LocalActorRef rather than the remoteActorRef

ActorRef vs selection

Wisdom on this is all over the place.

Seems to be that:

You have top level actor start everything up. Then when you have your actor refs you send them out in messages to all the actors

That need to talk to each other - get an ack from them that they are happy, and then start off the logic of your system.

Note actorref’s are serialised fine within messages.

Do not use actor paths as they can change if an actor dies and is restarted…

I did read someplace the following, but I think its wrong: “Do not use ActorRef, use actorSelection….an ActorRef can become wrong, eg if an actor dies and restarts. Whereas selection uses the path to find the action, and you can resolveOne with a timeout etc.”

Akka-http

http://doc.akka.io/docs/akka-stream-and-http-experimental/current/scala/http/index.html

All client-side functionality of Akka HTTP, for consuming HTTP-based services offered by other endpoints, is currently provided by the akka-http-core module.