Reputation: 2418
Is there any pattern for type checking an ActorRef
in Akka (scala)? When I pass a reference to another actor, I want to make sure it's of the correct type. However, when getting a reference, using the context
of an actor, it always returns ActorRef
, so I can't really use sub-classing to check this.
A concrete example follows. In Akka, I inject dependencies by passing ActorRef
into the constructor of another Actor
. Look at the contrived example below: Speaker
is constructed with a reference to Listener
. I create a props constructor in the companion object, as encouraged by the Akka documentation.
package test
import akka.actor._
object scratchpad {
object Speaker {
def apply(listener : ActorRef) : Props = Props(classOf[Speaker],listener)
}
class Speaker private(listener : ActorRef) extends Actor {
override def preStart() = listener ! "knock knock"
}
class Listener extends Actor {
def receive : Receive = {
case "knock knock" =>
//received message
}
}
val system = ActorSystem("test")
val listener = system.actorOf(Props[Listener])
val speaker = system.actorOf(Speaker(listener))
}
The problem is that I could create another actor, say DeafMute
, and pass this in instead - but the compiler wouldn't catch this, because it's also of type ActorRef
. Is there a pattern to work around this?
Upvotes: 3
Views: 1159
Reputation: 9635
There are some possibilities.
For one you could not pass the listener into the constructor but look it up using ActorSelection instead. For this you need to know the path however, this can be tricky depending on your actor hierarchy. I have not used this very much, but as looking up is asynchronous I expect you need to jump through some hoops to avoid timing issues and getting messages while not initialized yet. Also I think this might be a nuisance in unit tests.
Another approach I used in one of my projects was to create a factory that would return actorrefs depending on what kind of Actor I wanted. This can get messy though, when you consider actor hierarchies and temporary actors. This factory used dependency injection to create the actors and stored them internally to allow look-ups. Worked fine in our use case, very nice for unit test, since you could mock the factory and let it return testProbes easily. That takes some work to implement though, you need the IndirectActorProducer and some more stuff to make it work.
Other than that, the question is if this is really a problem. Normally you will have the "plumbing", i.e. connecting the actors, centralized, e.g. in parent nodes of the hierarchy. If you connected actors the wrong way your tests should catch that, also you can activate logging of unhandled messages. It takes some time to get used to it, but not having checks in place that the correct actors are connected is not so bad, you just need discipline and a good suite of tests. It is similar to the static vs. dynamic typing debate.
Upvotes: 3