Configuration Akka pattern

Typical Akka applications require configurable elements. And by those, I mean trivial things such as javax.sql.DataSources, javax.mail.Sessions and many others. We would like to keep our codebase the same accross environments; and by codebase, I also mean the configuration files. The main reason is that I can guarantee that at some point, someone will forget to update the configuration file on the production servers. (Go anecdotal evidence!) Now, in typical Java EE applications deployed in fat application servers (ugh!), we would use JNDI. Our code would lookup the JNDI elements, and we would configure the container with the right entries. Let’s explore the configuration options in Akka applications. As always, if you are impatient and want to see the code right now, head over to https://github.com/janm399/akka-patterns/wiki/Configuration for the Wiki and https://github.com/janm399/akka-patterns for the code.

We would like to somehow configure our Akka applications; keeping in mind that we will certainly want different configuration for our tests (and possibly different configuration for different tests!) and different configuration for the real running code. We would also like to be able to set up the configuration from our code and mix in the appropriate configuration. The word mix in should be a big hint. The actors (and other components) that want to access the configuration will need to mix in a trait that gives them the read only access; and the component that builds the configuration will need to mix in another trait that gives the write only access.

Turning to simple actor that uses a DataSource, we would have

import akka.actor.{Address, Actor}
import org.cakesolutions.akkapatterns.core.Configured
import javax.sql.DataSource

case class GetAddresses(person: String)

class AddressBookActor extends Actor with Configured {

  protected def receive = {
    case GetAddresses(person) =>
      val dataSource = configured[DataSource]

      // use the dataSource

      sender ! Address("Robert Robinson Avenue", "Oxford") ::
               Address("Houldsworth Mill", "Reddish") ::
               Nil
  }
}

Notice the configured[DataSource] function from the Configured trait: it looks for a configured instance that is assignable to DataSource and, if one exists, it returns it…

Now, to set up the environment, let’s take a look at how the *main* module would look like:

object Main extends App {

  implicit val system = ActorSystem("AkkaPatterns")

  class Application(val actorSystem: ActorSystem) extends 
    Core with Api with Web with Configuration {

    configure {
      val ds = new BasicDataSource()
      ds.setDriverClassName(classOf[JDBCDriver].getCanonicalName)
      ds.setUsername("sa")
      ds.setUrl("jdbc:hsqldb:mem:test")

      ds
    }
  }

  new Application(system)

  sys.addShutdownHook {
    system.shutdown()
  }

}

We say that the application is composed of Core, Api, Web and its DataSource is configured using the configure function from the Configuration trait. When we run this application (by executing the Main object), the AddressBookActor will use the HSQLDB DataSource at jdbc:hsqldb:mem:test. (Real applications will obviously want to use a “DataSource“ to a more powerful RDBMS, but the pattern will remain.)

This is the essence of the problem; detailed discussion is at https://github.com/janm399/akka-patterns/wiki/Configuration; the code is at https://github.com/janm399/akka-patterns.

This entry was posted in Jan's Blog and tagged , , . Bookmark the permalink.

One Response to Configuration Akka pattern

  1. Pingback: This week in #Scala (13/07/2012) | Cake Solutions Team Blog

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>