prose :: and :: conz


Akka and dependency injection: Child actors

As I mentioned a few weeks ago, I recently completed the Principles of Reactive Programming course on Coursera. After getting my feet thoroughly soaked in akka in the course, I began running with it in my day job. Akka will allow us to build a very good backend for handling our calls to the old-fashioned SOAP services which supply our application’s data. Over the weekend (yeah, I like my job THAT much) I began working on this and quickly discovered I didn’t readily know how to mock out children actors.

A quick Google search containing akka and any combination of the terms testing, dependency injection, and cake pattern shows that this is a lively discussion at this time. I dug around for a while and came up with several options which I highlight in this post.

Let me start with an explanation of what I’m looking for. As alluded to in the beginning of this post, I’m interested in unit testing my actors. The problem I’ve encountered occurs when I have an actor who by design creates child actors. I want to find a clean way to mock those out for testing while minimizing the impact on the production code. Hence, I’m not focused on finding a way to inject library APIs my actors may call and so forth.

Introduce the actors

The first option is to not explicitly create the actors as children. Instead, have whoever creates the parent actor also create the children and “introduce them” by passing the children actors via Props at construction time or by sending the child ActorRef(s) as messages after construction. This is evidently the preferred method of Reactive course instructor Roland Kuhn (unfortunately, I cannot find his Stackoverflow answer regarding this at the moment).

Well, I really don’t like that suggestion. Firstly, creating the child actors externally to the parent actor means that the creator has to know what actors to create. This could be really ugly if the actor has grandchildren too. This is one of the two biggest problems that I feel dependency injection solves. It allows encapsulation to be preserved. There are cases where passing the dependent actors makes a lot of sense, but again I’m talking about the case where they are child actors that you don’t want the instantiating code to be concerned with.

IndirectActorProducer

We always have the option to use a dependency injection framework like Guice or perhaps even Spring. In these cases, you would utilize the IndirectActorProducer to call your DI library.

Well, I’m not a big fan of this approach either. Firstly, I don’t have much experience with dependency injection anyway, as this post makes clear. Secondly, I feel that akka already solves the other big problem that dependency injection is useful for in the JVM world, namely coupling to the constructor. In both Java and Scala, there are constructs (interfaces and traits, respectively) which abstract the caller from the implementer of functionality. However, the one thing you cannot avoid with the languages alone is the constructor. The best you can do is put that construction code somewhere else, such as behind a factory. While dependency injection solves this problem, I feel like akka already has this under control thanks to Props. Actors can only be interacted with via the ActorRef trait, and it is the actor system’s job to instantiate the actors. The arguments for the constructor are passed via an instance of Props, hence removing any coupling to the actual implementing actor class. Because of this, I just don’t feel that a big dependency injection framework is worth the extra weight on my applications.

Bake a cake

Now for the coolest option I found… I stumbled across this usage of the cake pattern for handling dependency injection. While I have used the cake pattern thanks to Eugene Yokota‘s handy scalaxb which I utilize to generate my SOAP client code, I have never utilized the pattern in my own code. It seems to be a natural solution to this problem, as this pattern has long been cited as the way to go for dependency injection in Scala thanks to Jonas Bonér‘s relatively ancient article .

So I baked a cake, and it was awesome. I love the way the pattern works. However, there is a catch. Let’s take a look at this snippet from the Injecting Akka’s TestProbe in place of child actors article:

trait ChildrenProvider {
  def newFoo: Actor
}

trait ProductionChildrenProvider extends ChildrenProvider {
  def newFoo = new Foo
}

object Bar {
  def apply() = new Bar with ProductionChildrenProvider
}

class Bar extends Actor {
  this: ChildrenProvider =>
  val router = context.actorOf(Props(newFoo).
    withRouter(FromConfig()))
  def receive = {
    // ...
  }
}

The problem is line 15 where we see the creation of Props(newFoo). This newFoo function returns an Actor, NOT an ActorRef! This is a really bad thing, and would be deprecated if the akka developers can think of a way to support it differently. The gist of it is you should only let the akka system handle instantiations. I’d say even more importantly, you want your Props instances to be serializable and location-agnostic. An ActorRef can refer to an actor in a different JVM on a different machine altogether. If you are instantiating the actor yourself, then you’ve broken that ability.

I’d be curious to know if it will one day be possible to pass the trait mixin classes as arguments to Props. This may be what the aforementioned thread is referring to as a way to support this in the future.

ActorRefFactory => ActorRef

Finally, the approach I settled on is a variant of the approach described in this discussion. The idea is very simple, as it only utilizes that feature that Java so woefully lacks: functions.

I’ll use the code examples given in that post to explain this approach.

class ParentActor(makeChild: ActorRefFactory => ActorRef) 
  extends Actor {
  override def preStart() = {
    child = makeChild(context)
  }

  // ...
}

Our ParentActor has as an argument a function for instantiating its child actors. We can then provide two different implementations of this function, depending on whether we are testing or in production. The production version simply calls actorOf on the ActorRefFactory, which is then just a little indirection from the context object:

new ParentActor(_.actorOf(childProps))

The test version ignores the factory and returns whatever test probe actor you want:

new ParentActor((_: ActorRefFactory) => probeActor)

I actually took this a step further and included the Props as an input to this function, and gave the function type a name:

type Injector = (ActorRefFactory, Props) => ActorRef

This gives me the flexibility to make my test factory understand which child is being created, so we can reliably know which test probe is used as which child. It also looks better with the name. An actor constructor/declaration now takes this form:

class ParentActor(inj:Injector) extends Actor {
  // ...
}

Now, in the production example I borrowed above, he is instantiating the actor directly. Again, I believe this is certainly not the way you want to go. Instead, we should create a Props:

Props(classOf[ParentActor], ProductionInjector)

I suspect this still isn’t good. I’m not confident that this Props instance is serializable. In order to work around this, I thought it would be better if I used Props in production and called the constructor directly in test code, since there the principle behind it all isn’t important. What I eventually decided to try was having my Injector take the ProductionInjector as the default constructor argument shown here with the good-practice props() function in the companion object:

object ParentActor {
  val props = Props()
}
class ParentActor(inj:Injector = ProductionInjector) extends Actor {
  // ...
}

// Test code...
val actor = TestActorRef(new ParentActor(TestInjector))

The testing went great, and I am confident that my Props is indeed serializable. However, there’s a catch. This code doesn’t work in production! You’ll get an exception like this:

java.lang.IllegalArgumentException: no matching constructor found on
class com.joescii.ParentActor for arguments []

I think the problem is that Scala does not create two constructors for ParentActor in the byte code. Hence, no such constructor is available at runtime when akka tries to instantiate the actor via reflection. I suppose the default arguments are inserted during compile time at the site of invocation of the constructor. Firstly, this made me realize I need to test instantiating my actors via any props() factories I create, as I still want to construct the actors directly in the testing environment. Secondly, I realize this means I need to explicitly define two constructors. It’s not pretty, but at least it works.

Perhaps it doesn’t matter anyway

If you were look at my project right now, I’m not using child actors at all! Once I started working through the details, I figured out it just didn’t make sense for my use cases. Take for instance, my SOAP workers. I have one actor which is instantiated per user session, which facilitates the conversation between the client Angular/AJAX code and the worker actors who actually call the SOAP client code. I realized that I didn’t need a SOAP-handling actor per user. I could instead keep the authentication info associated with that user in his session’s actor, and pass it as part of the message to the workers. This way I am able to instead utilize an application-wide pool of workers, which is a far more efficient usage of resources.

In my case, it turns out that Kuhn is right in that one should reconsider the actor system design if you find yourself in need of actor injection (see Testing Actors and FSMs in Akka beginning at roughly 22:00. Thanks to this post by Tim Gilbert for pointing me to it). I came full circle and went back to the first suggestion which I initially shrugged off.


Olde Comments
  1. […] In order to abstract plumbing provided by two different bean types from both the service implementer and service caller, I created two Java interfaces for each end to interact with. First, the service would implement the ServiceImplementer interface which had a method with signature Serializable perform(Serializable param). This is equivalent to extending Actor in akka and implementing the receive method. It was up to the service to define the parameter object it could accept and the response object(s) (both of which we always called the model) . These are analogous to the messages in akka. The difference is that akka has the substantial benefit of case classes and default immutability afforded by Scala. Furthermore an akka actor is NOT required to respond with a message. The second interface was the ServiceProvider which the service caller would interact with to register for partial updates, responses, call synchronously, etc. This was the counterpart to akka’s ActorRef. The implementation of ServiceProvider navigates the catacombs of J2EE land on behalf of the caller to set up the service for the conversation. My library and akka shared this approach of utilizing the same interface for all actor implementations. I chose this design because I saw the method name as just a part of the serializable model/message getting passed to the service. Thanks to these abstractions in both my services library and akka, testing is a cinch. Every service can be easily mocked out for unit testing without the need for a dependency injection framework. While I had one good way of doing that for my services, there are several options for akka which I plan to expound upon in a future post. […]

  2. There is one possibility which you overlooked, which is using the cake pattern to inject not an Actor but an ActorRef. The slice of the cake which does it would declare a self type of Actor in order to access the `context` to create the child, while in testing it would just return a TestProbe.ref. If you go with injecting the Props (as I show in the lecture), then you can achieve the same by injecting a little forwarder actor which sends everything it receives to a given TestProbe.

    My point is that the possibilities are quite numerous, and there should be a solution for every half-way sane design ;-)

  3. FYI, some of the characters (> and <) are not encoded properly. At least for me.

    Thanks for the great work anyway. :-)

Tagged with: scala (41), akka (4), unit-testing (3), dependency-injection (2), test-driven-development (2)