There is an example in play framework doc (https://www.playframework.com/documentation/2.6.x/ScalaAkka) that explains how to inject actor (which has dependencies to be injected) into controller:
@Singleton
class Application @Inject()
(@Named("configured-actor") configuredActor: ActorRef)
(implicit ec: ExecutionContext) extends Controller {
implicit val timeout: Timeout = 5.seconds
def getConfig = Action.async {
(configuredActor ? GetConfig).mapTo[String].map { message =>
Ok(message)
}
}
}
But as I understand, it creates a single instance of the actor (e.g., singleton).
I need to create multiple instances of configuredActor
inside the controller.
There is also an example which demonstrates how to create child actors (which has dependencies to be injected) instances from parent actor
object ParentActor {
case class GetChild(key: String)
}
class ParentActor @Inject() (
childFactory: ConfiguredChildActor.Factory
) extends Actor with InjectedActorSupport {
import ParentActor._
def receive = {
case GetChild(key: String) =>
val child: ActorRef = injectedChild(childFactory(key), key)
sender() ! child
}
}
I've tried to apply this technique inside controller, but injectedChild(childFactory(key), key)
requires (implicitly) actor context
def injectedChild(create: => Actor, name: String, props: Props => Props = identity)(implicit context: ActorContext): ActorRef = ...
But I need to create this actor from ActorSysem (e.g. /user).
(I thought to get the context of /user
actor, but how? is that correct?)
What is a proper way to create multiple instances of an actor with Guice outside parent actor (for example, inside controller)?
I don't think there is a way of obtaining the ActorContext from outside of an actor, but if you like to create child actors from the /user actor you could do directly
system.actorOf
.The problem is like you said, that
InjectedActorSupport
needs an ActorContext. But if you look the trait, it doesn't do anything fancy, justSo, the solution is to extend the trait and add a method that receives the ActorSystem instead of the ActorContext.
In fact, you could even add the method to the controller directly but it is not convenient if you want to do this in multiples controllers.
UPDATE:
although this is technically correct I assumed (correctly) that the lack of a method that receives an ActorSystem was intended.
So, I've asked to the play dev team and James Roper has answered: