Clean up remote-deployed children when target node goes down, see #2550

* ClusterActorRefProvider watch remote deployed actors and sends
  ChildTerminated when AddressTerminated
* Added addressTerminated flag to Terminated to know when the Terminated
  was generated from a AddressTerminated
* Extra removal of child when the Terminated originates from AddressTerminated
  to support immediate creation of child with same name
This commit is contained in:
Patrik Nordwall 2012-09-26 14:02:21 +02:00
parent 4100c2d9b3
commit 8956523d5f
7 changed files with 134 additions and 12 deletions

View file

@ -5,19 +5,30 @@ package akka.cluster
import com.typesafe.config.Config
import akka.ConfigurationException
import akka.actor.Actor
import akka.actor.ActorPath
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.actor.ActorSystemImpl
import akka.actor.Deploy
import akka.actor.DynamicAccess
import akka.actor.InternalActorRef
import akka.actor.NoScopeGiven
import akka.actor.Props
import akka.actor.Scheduler
import akka.actor.Scope
import akka.actor.Terminated
import akka.cluster.routing.ClusterRouterConfig
import akka.cluster.routing.ClusterRouterSettings
import akka.dispatch.ChildTerminated
import akka.event.EventStream
import akka.remote.RemoteActorRefProvider
import akka.remote.RemoteDeployer
import akka.remote.routing.RemoteRouterConfig
import akka.cluster.routing.ClusterRouterSettings
/**
* INTERNAL API
*/
class ClusterActorRefProvider(
_systemName: String,
_settings: ActorSystem.Settings,
@ -26,10 +37,53 @@ class ClusterActorRefProvider(
_dynamicAccess: DynamicAccess) extends RemoteActorRefProvider(
_systemName, _settings, _eventStream, _scheduler, _dynamicAccess) {
@volatile private var remoteDeploymentWatcher: ActorRef = _
override def init(system: ActorSystemImpl): Unit = {
super.init(system)
remoteDeploymentWatcher = system.systemActorOf(Props[RemoteDeploymentWatcher], "RemoteDeploymentWatcher")
}
override val deployer: ClusterDeployer = new ClusterDeployer(settings, dynamicAccess)
/**
* This method is overridden here to keep track of remote deployed actors to
* be able to clean up corresponding child references.
*/
override def useActorOnNode(path: ActorPath, props: Props, deploy: Deploy, supervisor: ActorRef): Unit = {
super.useActorOnNode(path, props, deploy, supervisor)
remoteDeploymentWatcher ! (actorFor(path), supervisor)
}
}
/**
* INTERNAL API
*
* Responsible for cleaning up child references of remote deployed actors when remote node
* goes down (jvm crash, network failure), i.e. triggered by [[akka.actor.AddressTerminated]].
*/
private[akka] class RemoteDeploymentWatcher extends Actor {
var supervisors = Map.empty[ActorRef, InternalActorRef]
def receive = {
case (a: ActorRef, supervisor: InternalActorRef)
supervisors += (a -> supervisor)
context.watch(a)
case t @ Terminated(a) if supervisors isDefinedAt a
// send extra ChildTerminated to the supervisor so that it will remove the child
if (t.addressTerminated) supervisors(a).sendSystemMessage(ChildTerminated(a))
supervisors -= a
}
}
/**
* INTERNAL API
*
* Deployer of cluster aware routers.
*/
private[akka] class ClusterDeployer(_settings: ActorSystem.Settings, _pm: DynamicAccess) extends RemoteDeployer(_settings, _pm) {
override def parseConfig(path: String, config: Config): Option[Deploy] = {
super.parseConfig(path, config) match {