2
votes

I am an akka newbie and I'm trying to build an application that is composed of Spray and Akka. As part of the application I would like to give my fellow developers (who are also new to akka) some prepackaged actors that do specific things which they can then "attach" to their actor systems.

Specifically :

Is there a recommended way to provide a "actor locator"/"Actor System locator" -- think service locator like API to lookup and send messages to actors ? In other words How can I implement a function like:

ActorLocator.GoogleLocationAPIActor so that I can then use it like : ActorLocator.GoogleLocationAPIActor ! "StreetAddress"

Assume that getGoogleLocationAPIActor returns an ActorRef that accepts Strings that are addresses and makes an HTTP call to google to resolve that to a lat/lon.

I could internally use actorSelection, but :

  1. I would like to provide the GoogleLocationAPIActor as part of a library that my fellow developers can use
  2. #1 means that when my fellow developer builds an actor based application, he needs a way to tell the library code where the actor system is, so that the library can go an attach the actor to it (In keeping with the one actor system per application practice). Of course in a distributed environment, this could be a guardian for a cluster of actors that are running remotely.

Currently I define the ActorSystem in an object like and access it everywhere like

object MyStage{
    val system:ActorSystem = ActorSystem("my-stage")
}

then

object ActorLocator{
    val GoogleLocationAPIActor = MyStage.system.actorOf(Props[GoogleLocationAPI])
}

This approach seems to be similar to this but I'm not very sure if this is a good thing. My concerns are that the system seems too open for anyone to add children to without any supervision hierarchy, it seems a bit ugly.

Is my ask a reasonable one or Am I thinking about this wrong ?

How can we have "build up" a library of actors that we can reuse across apps ?

1

1 Answers

0
votes

Since this is is about designing an API, you're dangerously close to opinion territory but anyway, here is how I would be tempted to structure this. Personally I'm quite allergic to global singletons so:

Since ActorLocator is a service, I would organize it as a Trait:

trait ActorLocator {

  def GoogleLocationAPIActor: ActorRef
  def SomeOtherAPIActor: ActorRef

}

Then, you can have an implementation of the service such as:

class ActorLocatorLocalImpl(system: ActorSystem) extends ActorLocator {
  override lazy val GoogleLocationAPIActor: ActorRef =
    system.actorOf(Props[GoogleLocationAPI])

  //etc
}

And a Factory object:

object ActorLocator {
  def local(system: ActorSystem): ActorLocator = 
    new ActorLocatorLocalImpl(system)
}

If you need to create more complex implementations of the service and more complex factory methods, the users, having constructed a service, still just deal with the interface of the Trait.