make it possible to programmatically deploy (e.g. remotely), see #1644

- add Deploy to Props, which is used as the basis (overridden by
  configuration)
- utilize general mechanism .withFallback (introduced on Deploy,
  RouterConfig and Scope)
- actually pass Props over the wire when deploying remotely in order to
  retain settings (this was an oversight before)
- write tests for the new functionality
This commit is contained in:
Roland 2012-01-31 21:19:28 +01:00
parent 9d388f2de6
commit 10974acfe8
19 changed files with 360 additions and 88 deletions

View file

@ -112,8 +112,9 @@ class RemoteActorRefProvider(
terminationFuture.onComplete(_ transport.shutdown())
}
def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath, systemService: Boolean, deploy: Option[Deploy]): InternalActorRef = {
if (systemService) local.actorOf(system, props, supervisor, path, systemService, deploy)
def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath,
systemService: Boolean, deploy: Option[Deploy], lookupDeploy: Boolean): InternalActorRef = {
if (systemService) local.actorOf(system, props, supervisor, path, systemService, deploy, lookupDeploy)
else {
/*
@ -152,22 +153,33 @@ class RemoteActorRefProvider(
}
val elems = path.elements
val deployment = deploy orElse (elems.head match {
case "user" deployer.lookup(elems.drop(1).mkString("/", "/", ""))
case "remote" lookupRemotes(elems)
case _ None
})
val lookup =
if (lookupDeploy)
elems.head match {
case "user" deployer.lookup(elems.drop(1).mkString("/", "/", ""))
case "remote" lookupRemotes(elems)
case _ None
}
else None
deployment match {
case Some(Deploy(_, _, _, RemoteScope(addr)))
if (addr == rootPath.address) local.actorOf(system, props, supervisor, path, false, deployment)
else {
val deployment = {
lookup.toList ::: deploy.toList ::: Nil match {
case Nil Nil
case l List(l reduceRight (_ withFallback _))
}
}
deployment ::: props.deploy :: Nil reduceRight (_ withFallback _) match {
case d @ Deploy(_, _, _, RemoteScope(addr))
if (addr == rootPath.address || addr == transport.address) {
local.actorOf(system, props, supervisor, path, false, deployment.headOption, false)
} else {
val rpath = RootActorPath(addr) / "remote" / transport.address.hostPort / path.elements
useActorOnNode(rpath, props.creator, supervisor)
useActorOnNode(rpath, props, d, supervisor)
new RemoteActorRef(this, transport, rpath, supervisor)
}
case _ local.actorOf(system, props, supervisor, path, systemService, deployment)
case _ local.actorOf(system, props, supervisor, path, systemService, deployment.headOption, false)
}
}
}
@ -188,11 +200,11 @@ class RemoteActorRefProvider(
/**
* Using (checking out) actor on a specific node.
*/
def useActorOnNode(path: ActorPath, actorFactory: () Actor, supervisor: ActorRef) {
def useActorOnNode(path: ActorPath, props: Props, deploy: Deploy, supervisor: ActorRef) {
log.debug("[{}] Instantiating Remote Actor [{}]", rootPath, path)
// we dont wait for the ACK, because the remote end will process this command before any other message to the new actor
actorFor(RootActorPath(path.address) / "remote") ! DaemonMsgCreate(actorFactory, path.toString, supervisor)
actorFor(RootActorPath(path.address) / "remote") ! DaemonMsgCreate(props, deploy, path.toString, supervisor)
}
}