How we can build a close interaction between Actors? Just with help of messaging. In the previous post I’ve already demonstrated how we can send messages between Actors. In this post I want to continue topic of message exchange, but this time let’s develop cooperation of two Actors which interact with each other.

How we can force an Actor A to send a message to Actor B? We can use the tell(message, sender) method. But this approach implies an explicit invocation of the method. In order to send a message from A to B as a reaction on something, we need to path ActorRef of B to A. This can be done with help of constructor or message.

That’s the code of the TesterActor:

import akka.actor.{Props, Actor}
import akka.event.Logging
import com.actor.DeveloperActor.{Fix, Bug, NewFeature}

import scala.util.Random

class TesterActor extends Actor {

  val log = Logging.getLogger(context.system, this)

  def receive = {
    case feature: NewFeature => {
      log.info(s"Testing '${feature.name}'...")
      val bugExists = Random.nextInt(10)
      if (bugExists > 7) {
        log.info("A bug was found")
        sender() ! Bug
      }
    }
    case Fix => log.info(s"Verifying the fix...")
    case _ => log.info("Watching YouTube")
  }

}

object TesterActor {
  def props = Props(new TesterActor)
}

It represents a software tester. It’s behavior is pretty natural. So the tester can process 3 cases:

  • New feature received. The tester starts its testing. There is probability that the tester will find a bug. As a result it sends the bug to the developer who worked on this feature and it need to fix it.
    If there is no any bugs were found, nothing happens next.
  • A fix received. The tester verifies it.
  • Some other message received. The tester watches YouTube.

Let’s look at the DeveloperActor:

import akka.actor.{ActorRef, Props, Actor}
import akka.event.Logging

class DeveloperActor(tester: ActorRef) extends Actor {
  import DeveloperActor._
  val log = Logging.getLogger(context.system, this)

  def receive = {
    case feature: NewFeature => {
      log.info(s"Working on feature '${feature.name}'")
      tester ! feature
    }
    case Bug => {
      log.info("Fixing a bug")
      tester ! Fix
    }
    case _ => log.info("Playing StarCraft2")
  }

}

object DeveloperActor {

  def props(tester: ActorRef) = Props(new DeveloperActor(tester))

  case class NewFeature(name: String)
  object Bug
  object Fix

}

There are two things which I want to emphasize:

  • The Actor has the argument in the constructor.
  • When the Actor receive the NewFeature it sends it to the Actor passed as the constructor argument.

Finally here is a demonstration:

import akka.actor.ActorSystem
import com.actor.DeveloperActor.NewFeature

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

    val system = ActorSystem.create("outsource-company")

    val tester = system.actorOf(TesterActor.props, "Sam")
    val developer = system.actorOf(DeveloperActor.props(tester), "Bob")

    developer ! NewFeature("Social integration")

    system.terminate()

  }
}

There are two possible results for the code snippet above:

...[akka://outsource-company/user/Bob] Working on feature 'Social integration'
...[akka://outsource-company/user/Sam] Testing 'Social integration'...
...[akka://outsource-company/user/Sam] A bug was found
...[akka://outsource-company/user/Bob] Fixing a bug
...[akka://outsource-company/user/Sam] Verifying the fix...

and

...[akka://outsource-company/user/Bob] Working on feature 'Social integration'
...[akka://outsource-company/user/Sam] Testing 'Social integration'...

That’s how we can use constructors for passing some values in the Actors. Also it’s very important to know how to send messages directly from Actors and how to send responses to them.
Thanks for reading.

About The Author

Mathematician, programmer, wrestler, last action hero… Java / Scala architect, trainer, entrepreneur, author of this blog

Close