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:
parent
4100c2d9b3
commit
8956523d5f
7 changed files with 134 additions and 12 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue