Actor's in Action with Akka

 

 

Actor model

  • Make local decisions.
  • Send messages to other actors.
  • Create new actors.
  • Designate the behavior to be used for the next message it receives.
  • Fundamental Unit of Computation

The actor

  • Force Immutability
  • Fundamental communication mechanism

The message

The system

Purpose

  • Asynchronous by default
  • Immutable states

 

 

Concurrency

Akka in scala

Defining the system

The Message

case class User(name: String, surname: String)

 

  • Immutable by default
  • Getters automatically defined
  • Compliant equals(), hashCode() and toString() implementation
  • Compliant serialize()/deserialize()

 

The Actor

class MyActor extends Actor {
  def receive = {
  
      // Matches any string at all
      case s: String =>
        println(s"You sent me a string: $s")
  
      // Match a more complex case class structure
      case user: User =>
        println(s"You sent me a user: $user")
  
      // Catch all. Matches any message type
      case _ =>
        println("Huh?")
    }
}

The System

val system = ActorSystem("MyActorSystem")
val system = ActorSystem("MyActorSystem")
val myActor: ActorRef = system.actorOf(Props[MyActor], name = "myActor")

 

  • Props: Configuration class to specify options in the creation of actors

 

  • ActorRef: Untyped reference to an actor. Encapsulates the actor behind a layer of abstraction.

All together now

object App {

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("MyActorSystem")
    val myActor: ActorRef = system.actorOf(Props[MyActor], name = "myActor")

    myActor ! User("Borja", "Gorriz")
  }
}

class MyActor extends Actor {
  def receive = {

    // Match a more complex case class structure
    case user: User =>
      println(s"You sent me a user: $user ")
  }
}

case class User(name: String, surname: String)

Sending messages

The tell

myActor ! User("Borja", "Gorriz")

The tell

object App {

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("MyActorSystem")
    val myActor: ActorRef = system.actorOf(Props[MyActor], name = "myActor")

    myActor ! User("Borja", "Gorriz")
  }
}

class MyActor extends Actor {
  def receive = {

    // Match a more complex case class structure
    case user: User =>
      println(s"You sent me a user: $user ")
  }
}

case class User(name: String, surname: String)

The ask

myActor ? User("Borja", "Gorriz")

The ask

object App {

  def main(args: Array[String]): Unit = {

    val system = ActorSystem("MyActorSystem")
    val myActor = system.actorOf(Props[MyActor], name = "myActor")

    implicit val askTimeout = Timeout(1.second)
    (myActor ? User("Borja", "Gorriz")).mapTo[String]
         .onSuccess({ case response: String => println(response) })
  }
}

class MyActor extends Actor {
  def receive = {
    case s: String =>
      println(s"You sent me a string: $s")
    case user: User =>
      self ! "just created a user"
      sender() ! s"New $user created"
  }
}

case class User(name: String, surname: String)

The forward

myActor.forward(User("Borja", "Gorriz"))
object App {
  def main(args: Array[String]): Unit = {
    val system = ActorSystem("MyActorSystem")
    val RootActor = system.actorOf(Props[RootActor], name = "RootActor")
    
    RootActor ! User("Borja", "Gorriz")
  }
}
class RootActor() extends Actor {
  def receive = {
    case user: User =>
      val forwardActor = context.actorOf(Props[ForwardActor])
      forwardActor ! user
    case msg: String => println(s"Result: $msg")
  }
}
class ForwardActor() extends Actor {
  def receive = {
    case user: User =>
      val myActor = context.actorOf(Props[MyActor])
      myActor.forward(user)
  }
}
class MyActor extends Actor {
  def receive = {
    case user: User =>
      sender() ! s"New $user created"
  }
}
case class User(name: String, surname: String)

The pipe

pipe(Future) to MyActor
object App {

  def main(args: Array[String]): Unit = {
    val system = ActorSystem("MyActorSystem")
    val pipeActor = system.actorOf(Props[PipeActor], name = "pipeActor")
    implicit val askTimeout = Timeout(1.second)
    (pipeActor ? User("Borja","Gorriz"))
    .mapTo[String].onSuccess({ case response: String => println(response) })
  }
}
class MyActor extends Actor {
  def receive = {
    case user: User =>
      sender() ! s"New $user created"
  }
}
class PipeActor() extends Actor {
  def receive = {
    case user: User =>
      implicit val askTimeout = Timeout(1.second)
      val myActor = context.actorOf(Props[MyActor])
      pipe(myActor ? user) to sender()
    case _ =>
  }
}
case class User(name: String, surname: String)

Patterns & best practices

Boot up

object Boot extends App {

    val system = ActorSystem("MyActorSystem")
    //now we can just start building actors   
}


Actor creation

object DemoActor {
  def props(magicNumber: Int): Props = Props(new DemoActor(magicNumber))
} 
class DemoActor(magicNumber: Int) extends Actor {
  def receive = {
    case x: Int => sender() ! (x + magicNumber)
  }
}
 
class SomeOtherActor extends Actor {
   context.actorOf(DemoActor.props(42), "demo")
}

tell, don't ask

tell, don't ask

resources

thank you

akka

By Borja Gorriz Hernando