days
-4
-6
hours
0
-7
minutes
-1
-2
seconds
-1
-6
search
JAX Developers Puzzle deadline approaching: Play for a chance to win a complimentary JAX London 2018 ticket!
Things you should be aware of

Akka anti-patterns: overusing ActorSelection

Manuel Bernhardt
akka
© Shutterstock / wk1003mike

In this part of Manuel Bernhardt’s series on Akka anti-patterns, we have a look at the things that you should keep in mind when using the ActorSelection mechanism.

Akka’s ActorSelection makes it possible to look up actors by logical path in the hierarchy:

val selection: ActorSelection = context.actorSelection("../processor/storage")
 

This selection can then be used like ActorRef in order to send messages to it using the tell or askpatterns:

selection ! Storage.Store("important words")
 
val allWords: Future[Seq[String]] = selection ? Storage.RetrieveAll
 

ActorSelection is therefore quite useful and allows more flexibility when designing an actor system given that trees can be built dynamically and queried dynamically at runtime. That being said, there are a few things that you should be aware of when using this mechanism.

ActorSelection is unverified

When you hold an ActorRef in your hands, you have something concrete and substantial and chances are high that the actor it points to exists (unless it has been stopped in the meanwhile). With ActorSelection there is no such guarantee: make a typo in the path, and you will notice only when sending messages to the selection – if you happen to watch closely the dead letter logs. What’s more, if you overuse this feature and tend to write out (hardcode) actor paths all across your application, this might become a source of headache as the application grows and changes in case you rename actors or move them around in your hierarchy.

ActorSelection is less performant than ActorRef

The way that ActorSelection works is that it will do the lookup at message delivery time, for each message sent. That might be alright if you are sending a few messages, but if you send many messages and have a deep hierarchy to traverse, you are paying unnecessary lookup costs every time.

Use Identify when appropriate

If your actor needs to dynamically resolve another actor and then send it plenty of messages, a solution is to use the built-in Identify message that, when sent to an ActorSelection, will give you back the ActorRef – or nothing at all, if the ActorSelection doesn’t match anything. The good news is that it always gives you back an answer (of type ActorIdentity) so you know what is going on. Combine this technique with context.become and you get a simple way to safely bootstrap actors that use this mechanism:

class ResolvingActor extends Actor with Stash with ActorLogging {
  val CorrelationId = 42
  var storage: Option[ActorRef] = None
 
  context.actorSelection("../processor/storage") ! Identify(CorrelationId)
 
  def receive = initializing()
 
  def initializing(): Receive = {
    case ActorIdentity(CorrelationId, Some(ref)) =>
      storage = Some(ref)
      unstashAll()
      context.become(ready())
    case ActorIdentity(CorrelationId, None) =>
      log.error("Storage not ready, unable to process requests")
      context.stop(self)
    case _ =>
      stash()
  }
 
  def ready(): Receive = {
    case StoreSomething(message) =>
      // do the usual processing
      storage.foreach(_ ! Storage.Store(message))
  }
}
 

In conclusion, overusing ActorSelection means one of two things:

  • using it in too many places, with hardcoded paths that are tricky to maintain
  • using it to send too many messages as it has a performance cost

This post was originally published on Manuel Bernhardt’s blog.

Author
akka

Manuel Bernhardt

Manuel Bernhardt is a passionate engineer, author, speaker and consultant who has a keen interest in the science of building and operating networked applications that run smoothly despite their distributed nature. Since 2008, he has guided and trained enterprise teams on the transformation to distributed computing. In recent years he is focusing primarily on production systems that embrace the reactive application architecture, using Scala, Play Framework and Akka to this end. Manuel likes to travel and is a frequent speaker at international conferences. He lives in Vienna where he is a co-organizer of the Scala Vienna User Group. Next to thinking, talking about and fiddling with computers he likes to spend time with his family, run, scuba-dive and read. You can find out more about Manuel’s recent work at http://manuel.bernhardt.io.


Leave a Reply

Be the First to Comment!

avatar
400
  Subscribe  
Notify of