I am trying to refactor an Akka application from a single tier to multi-tier structure with akka clustering (http://doc.akka.io/docs/akka/2.3.9/scala/cluster-usage.html). Within the application are some actors that have a parameterized default constructor, e.g.
class MyActor(someParam: boolean = true) extends Actor {
def receive = { /* message handling here... */ }
}
I am now trying to create a generic router actor that will route to a node with a specific node. The cluster configuration is working based of the example on the akka site, and I can create a router in 1 role that routes to the actor in another role:
class MyActorProxy extends Actor {
val workerRouter = context.actorOf(FromConfig.props(Props(classOf[MyActor]), name = "workerRouter")
def receive = {
case msg: Any =>
val currentSender = sender()
workerRouter.tell(msg, currentSender)
}
}
This method works as needed. However, I need to go and create a handful of proxy classes with the same functionality, and it's painful. I'm trying to make it work better, and limited scala experience is making it difficult. Here's what I am trying to do:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props(classOf[T])),name=routerPath)
def receive = {
case msg: Any => {
val currentSender = sender()
router.tell(msg,currentSender)
}
}
}
class MyActorProxy extends RouterProxy[MyActor](routerPath = "myActorRouter")
Have come up with this by reading through some scala docs and through stackoverflow, but can't seem to get it right - this approach doesn't let me create the props for the actor. I've seen How to instantiate an instance of type represented by type parameter in Scala and I think that the type information is being lost (type erasure).
How would I go about passing an actor class to the router proxy to allow for router initialization?
This is the error I get during compilation, while initializing the router:
class type required but T found
edit
Background for using a generic proxy router
The reason for this approach is to refactor the application for both single tier and multi-tier architecture. When running multi-tier, I want to skip initializing any "heavy" actors. Given I have the following config on a frontend node:
akka.actor.deployment {
/workerRouter {
routee.paths = ["/user/myActor"]
cluster.use-role = backend
}
}
akka.cluster.roles = [frontend]
and the backend node has roles of [backend]
, then when I start up frontend nodes, MyActor will not be initialized. MyActor is an example of 1 of many actors that are supervisors / managers. Each 1 of them might initialize a few other actors in turn (sometimes with routers). What I'm trying to do is refactor the application so I can run lightweight frontend nodes in a different tier to resource heavy backend nodes if I need to, but also still have the ability to run all on a single node. By this approach, I can add in initialization for heavy managers into my application bootstrap and add a role and it becomes a multifunctional app without needing recoding.
edit 2 I am able to get the application to work as expected if the class constructor doesn't take any arguments.
MyActor extends Actor { /* ... */ }
And then in my abstract class:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props[T]),name = routerPath)
}
Props[MyActor]
works fine for a parameterless actor, but Props(classOf[T])
looses the type.