ActorSelection
is really the way to replace actorFor
. However, as I've already stated in the book, using Actor paths or selections can make your app quite brittle.
context.actorSelection("../someactor") ! ReadyToGo
context.actorSelection(self / "someChild" / "someGrandchild") ! ReadyToGo
Change your actor hierarchy, and your app starts failing. However, at least with ActorSelection
you get some timeout errors instead of just getting things sent to the dead letter office.
Now, if you want to start grabbing references, that's a different story and I suggest doing it with Future
s.
import akka.actor._
import akka.pattern.pipe
class MyActor extends Actor with Stash {
val actors = for {
actorA <- ActorSelection(someRootActor / List("child1", "grandchild", "greatGrandchild")).resolveOne()
actorB <- ActorSelection(someRootActor / List("child2")).resolveOne()
actorC <- ActorSelection(someOtherRootActor / List("childC")).resolveOne()
} yield ActorsLocated(actorA, actorB, actorC)
actors recover {
case t: Throwable =>
ActorLocatingFailed(t)
} pipeTo self
val uninitialized: Receive = {
case ActorsLocated(a, b, c) =>
unstashAll()
context.become(initialized(a, b, c))
case ActorLocatingFailed(reason) =>
throw new IllegalStateException(s"Failed to initialize: $reason")
case _ =>
stash()
}
def initalized(a: ActorRef, b: ActorRef, c: ActorRef): Receive = {
// do your stuff here
}
def receive = uninitialized
}
Now you have a fully asynchronous startup for your Actor that grabs all of its dependencies properly. On restart, you're good to go.