2011-09-15 10:20:18 +02:00
|
|
|
|
/**
|
2013-01-09 01:47:48 +01:00
|
|
|
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
2011-09-15 10:20:18 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
2011-09-20 21:44:50 +02:00
|
|
|
|
package akka.remote
|
2011-09-15 10:20:18 +02:00
|
|
|
|
|
|
|
|
|
|
import akka.actor._
|
2013-03-05 16:19:54 +01:00
|
|
|
|
import akka.dispatch.sysmsg._
|
2012-07-06 17:04:04 +02:00
|
|
|
|
import akka.event.{ Logging, LoggingAdapter, EventStream }
|
2012-08-16 11:31:53 +02:00
|
|
|
|
import akka.event.Logging.Error
|
2013-01-28 14:38:33 +01:00
|
|
|
|
import akka.serialization.{ JavaSerializer, Serialization, SerializationExtension }
|
2012-12-14 16:09:38 +01:00
|
|
|
|
import akka.pattern.pipe
|
2012-08-16 11:31:53 +02:00
|
|
|
|
import scala.util.control.NonFatal
|
2012-12-14 16:09:38 +01:00
|
|
|
|
import akka.actor.SystemGuardian.{ TerminationHookDone, TerminationHook, RegisterTerminationHook }
|
2013-01-27 12:56:35 +01:00
|
|
|
|
import scala.util.control.Exception.Catcher
|
2013-01-31 02:16:39 +01:00
|
|
|
|
import scala.concurrent.{ ExecutionContext, Future }
|
2013-03-27 17:47:56 +01:00
|
|
|
|
import scala.concurrent.forkjoin.ThreadLocalRandom
|
2013-04-15 09:26:51 +02:00
|
|
|
|
import com.typesafe.config.Config
|
|
|
|
|
|
import akka.ConfigurationException
|
2012-12-14 16:09:38 +01:00
|
|
|
|
|
2013-02-08 13:13:52 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* INTERNAL API
|
|
|
|
|
|
*/
|
|
|
|
|
|
private[akka] object RemoteActorRefProvider {
|
2012-12-14 16:09:38 +01:00
|
|
|
|
private case class Internals(transport: RemoteTransport, serialization: Serialization, remoteDaemon: InternalActorRef)
|
|
|
|
|
|
|
|
|
|
|
|
sealed trait TerminatorState
|
|
|
|
|
|
case object Uninitialized extends TerminatorState
|
|
|
|
|
|
case object Idle extends TerminatorState
|
|
|
|
|
|
case object WaitDaemonShutdown extends TerminatorState
|
|
|
|
|
|
case object WaitTransportShutdown extends TerminatorState
|
|
|
|
|
|
case object Finished extends TerminatorState
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
private class RemotingTerminator(systemGuardian: ActorRef) extends Actor with FSM[TerminatorState, Option[Internals]] {
|
2012-12-14 16:09:38 +01:00
|
|
|
|
import context.dispatcher
|
|
|
|
|
|
|
|
|
|
|
|
startWith(Uninitialized, None)
|
|
|
|
|
|
|
|
|
|
|
|
when(Uninitialized) {
|
|
|
|
|
|
case Event(i: Internals, _) ⇒
|
2012-12-18 12:54:17 +01:00
|
|
|
|
systemGuardian ! RegisterTerminationHook
|
2012-12-14 16:09:38 +01:00
|
|
|
|
goto(Idle) using Some(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
when(Idle) {
|
|
|
|
|
|
case Event(TerminationHook, Some(internals)) ⇒
|
|
|
|
|
|
log.info("Shutting down remote daemon.")
|
|
|
|
|
|
internals.remoteDaemon ! TerminationHook
|
|
|
|
|
|
goto(WaitDaemonShutdown)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: state timeout
|
|
|
|
|
|
when(WaitDaemonShutdown) {
|
|
|
|
|
|
case Event(TerminationHookDone, Some(internals)) ⇒
|
2012-12-18 12:54:17 +01:00
|
|
|
|
log.info("Remote daemon shut down; proceeding with flushing remote transports.")
|
2012-12-14 16:09:38 +01:00
|
|
|
|
internals.transport.shutdown() pipeTo self
|
|
|
|
|
|
goto(WaitTransportShutdown)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
when(WaitTransportShutdown) {
|
|
|
|
|
|
case Event((), _) ⇒
|
|
|
|
|
|
log.info("Remoting shut down.")
|
2012-12-18 12:54:17 +01:00
|
|
|
|
systemGuardian ! TerminationHookDone
|
2012-12-14 16:09:38 +01:00
|
|
|
|
stop()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2013-01-28 14:38:33 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Remoting wraps messages destined to a remote host in a remoting specific envelope: EndpointManager.Send
|
|
|
|
|
|
* As these wrapped messages might arrive to the dead letters of an EndpointWriter, they need to be unwrapped
|
|
|
|
|
|
* and handled as dead letters to the original (remote) destination. Without this special case, DeathWatch related
|
|
|
|
|
|
* functionality breaks, like the special handling of Watch messages arriving to dead letters.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private class RemoteDeadLetterActorRef(_provider: ActorRefProvider,
|
|
|
|
|
|
_path: ActorPath,
|
|
|
|
|
|
_eventStream: EventStream) extends DeadLetterActorRef(_provider, _path, _eventStream) {
|
2013-03-27 17:47:56 +01:00
|
|
|
|
import EndpointManager.Send
|
2013-01-28 14:38:33 +01:00
|
|
|
|
|
|
|
|
|
|
override def !(message: Any)(implicit sender: ActorRef): Unit = message match {
|
2013-03-27 17:47:56 +01:00
|
|
|
|
case Send(m, senderOption, _, seqOpt) ⇒
|
|
|
|
|
|
// else ignore: it is a reliably delivered message that might be retried later, and it has not yet deserved
|
|
|
|
|
|
// the dead letter status
|
|
|
|
|
|
if (seqOpt.isEmpty) super.!(m)(senderOption.orNull)
|
|
|
|
|
|
case DeadLetter(Send(m, senderOption, recipient, seqOpt), _, _) ⇒
|
|
|
|
|
|
// else ignore: it is a reliably delivered message that might be retried later, and it has not yet deserved
|
|
|
|
|
|
// the dead letter status
|
|
|
|
|
|
if (seqOpt.isEmpty) super.!(m)(senderOption.orNull)
|
|
|
|
|
|
case _ ⇒ super.!(message)(sender)
|
2013-01-28 14:38:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@throws(classOf[java.io.ObjectStreamException])
|
|
|
|
|
|
override protected def writeReplace(): AnyRef = DeadLetterActorRef.serialized
|
|
|
|
|
|
}
|
2012-12-14 16:09:38 +01:00
|
|
|
|
}
|
2011-09-19 14:43:28 +02:00
|
|
|
|
|
2011-09-15 10:20:18 +02:00
|
|
|
|
/**
|
2013-02-08 13:13:52 +01:00
|
|
|
|
* INTERNAL API
|
|
|
|
|
|
* Depending on this class is not supported, only the [[akka.actor.ActorRefProvider]] interface is supported.
|
2012-11-26 17:42:25 +01:00
|
|
|
|
*
|
2013-02-08 13:13:52 +01:00
|
|
|
|
* Remote ActorRefProvider. Starts up actor on remote node and creates a RemoteActorRef representing it.
|
2012-11-26 17:42:25 +01:00
|
|
|
|
*
|
2011-09-15 10:20:18 +02:00
|
|
|
|
*/
|
2013-02-08 13:13:52 +01:00
|
|
|
|
private[akka] class RemoteActorRefProvider(
|
2011-11-29 16:32:50 +01:00
|
|
|
|
val systemName: String,
|
2011-11-17 11:51:14 +01:00
|
|
|
|
val settings: ActorSystem.Settings,
|
2011-11-14 14:21:53 +01:00
|
|
|
|
val eventStream: EventStream,
|
2012-02-10 11:36:23 +01:00
|
|
|
|
val dynamicAccess: DynamicAccess) extends ActorRefProvider {
|
2012-12-14 16:09:38 +01:00
|
|
|
|
import RemoteActorRefProvider._
|
2011-09-15 10:20:18 +02:00
|
|
|
|
|
2013-01-17 16:19:31 +01:00
|
|
|
|
val remoteSettings: RemoteSettings = new RemoteSettings(settings.config)
|
2011-12-08 14:44:05 +01:00
|
|
|
|
|
2012-11-15 12:48:13 +01:00
|
|
|
|
override val deployer: Deployer = createDeployer
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Factory method to make it possible to override deployer in subclass
|
|
|
|
|
|
* Creates a new instance every time
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected def createDeployer: RemoteDeployer = new RemoteDeployer(settings, dynamicAccess)
|
2012-01-27 12:14:28 +01:00
|
|
|
|
|
2013-03-30 01:03:17 +01:00
|
|
|
|
private val local = new LocalActorRefProvider(systemName, settings, eventStream, dynamicAccess, deployer,
|
2013-01-31 09:24:12 +01:00
|
|
|
|
Some(deadLettersPath ⇒ new RemoteDeadLetterActorRef(this, deadLettersPath, eventStream)))
|
2012-01-27 12:14:28 +01:00
|
|
|
|
|
|
|
|
|
|
@volatile
|
|
|
|
|
|
private var _log = local.log
|
|
|
|
|
|
def log: LoggingAdapter = _log
|
|
|
|
|
|
|
2012-11-22 14:40:54 +01:00
|
|
|
|
override def rootPath: ActorPath = local.rootPath
|
2013-01-31 09:24:12 +01:00
|
|
|
|
override def deadLetters: InternalActorRef = local.deadLetters
|
2012-01-27 12:14:28 +01:00
|
|
|
|
|
|
|
|
|
|
// these are only available after init()
|
2012-05-24 11:44:39 +02:00
|
|
|
|
override def rootGuardian: InternalActorRef = local.rootGuardian
|
2012-06-19 14:52:02 +02:00
|
|
|
|
override def guardian: LocalActorRef = local.guardian
|
|
|
|
|
|
override def systemGuardian: LocalActorRef = local.systemGuardian
|
2012-07-06 17:04:04 +02:00
|
|
|
|
override def terminationFuture: Future[Unit] = local.terminationFuture
|
2012-05-24 11:44:39 +02:00
|
|
|
|
override def registerTempActor(actorRef: InternalActorRef, path: ActorPath): Unit = local.registerTempActor(actorRef, path)
|
|
|
|
|
|
override def unregisterTempActor(path: ActorPath): Unit = local.unregisterTempActor(path)
|
|
|
|
|
|
override def tempPath(): ActorPath = local.tempPath()
|
|
|
|
|
|
override def tempContainer: VirtualPathContainer = local.tempContainer
|
2012-01-18 11:52:35 +01:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
@volatile private var _internals: Internals = _
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
2012-12-14 16:09:38 +01:00
|
|
|
|
def transport: RemoteTransport = _internals.transport
|
|
|
|
|
|
def serialization: Serialization = _internals.serialization
|
|
|
|
|
|
def remoteDaemon: InternalActorRef = _internals.remoteDaemon
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
2012-12-14 16:09:38 +01:00
|
|
|
|
// This actor ensures the ordering of shutdown between remoteDaemon and the transport
|
2013-04-15 09:26:51 +02:00
|
|
|
|
@volatile private var remotingTerminator: ActorRef = _
|
|
|
|
|
|
|
|
|
|
|
|
@volatile private var remoteWatcher: ActorRef = _
|
|
|
|
|
|
@volatile private var remoteDeploymentWatcher: ActorRef = _
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
2012-05-24 11:44:39 +02:00
|
|
|
|
def init(system: ActorSystemImpl): Unit = {
|
2011-12-08 14:44:05 +01:00
|
|
|
|
local.init(system)
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
remotingTerminator = system.systemActorOf(Props(classOf[RemotingTerminator], local.systemGuardian), "remoting-terminator")
|
2012-12-14 16:09:38 +01:00
|
|
|
|
|
|
|
|
|
|
val internals = Internals(
|
|
|
|
|
|
remoteDaemon = {
|
|
|
|
|
|
val d = new RemoteSystemDaemon(
|
|
|
|
|
|
system,
|
|
|
|
|
|
local.rootPath / "remote",
|
|
|
|
|
|
rootGuardian,
|
|
|
|
|
|
remotingTerminator,
|
|
|
|
|
|
log,
|
|
|
|
|
|
untrustedMode = remoteSettings.UntrustedMode)
|
|
|
|
|
|
local.registerExtraNames(Map(("remote", d)))
|
|
|
|
|
|
d
|
|
|
|
|
|
},
|
|
|
|
|
|
serialization = SerializationExtension(system),
|
2013-01-17 16:19:31 +01:00
|
|
|
|
transport = new Remoting(system, this))
|
2012-12-14 16:09:38 +01:00
|
|
|
|
|
|
|
|
|
|
_internals = internals
|
2012-12-18 12:54:17 +01:00
|
|
|
|
remotingTerminator ! internals
|
2012-01-27 12:14:28 +01:00
|
|
|
|
|
2012-09-12 11:18:42 +02:00
|
|
|
|
_log = Logging(eventStream, "RemoteActorRefProvider")
|
2012-01-27 12:14:28 +01:00
|
|
|
|
|
|
|
|
|
|
// this enables reception of remote requests
|
2012-12-14 16:09:38 +01:00
|
|
|
|
transport.start()
|
2012-01-20 14:29:50 +01:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
remoteWatcher = createRemoteWatcher(system)
|
|
|
|
|
|
remoteDeploymentWatcher = createRemoteDeploymentWatcher(system)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected def createRemoteWatcher(system: ActorSystemImpl): ActorRef = {
|
|
|
|
|
|
import remoteSettings._
|
|
|
|
|
|
val failureDetector = createRemoteWatcherFailureDetector(system)
|
|
|
|
|
|
system.systemActorOf(RemoteWatcher.props(
|
|
|
|
|
|
failureDetector,
|
|
|
|
|
|
heartbeatInterval = WatchHeartBeatInterval,
|
|
|
|
|
|
unreachableReaperInterval = WatchUnreachableReaperInterval,
|
|
|
|
|
|
heartbeatExpectedResponseAfter = WatchHeartbeatExpectedResponseAfter,
|
|
|
|
|
|
numberOfEndHeartbeatRequests = WatchNumberOfEndHeartbeatRequests), "remote-watcher")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected def createRemoteWatcherFailureDetector(system: ExtendedActorSystem): FailureDetectorRegistry[Address] = {
|
|
|
|
|
|
def createFailureDetector(): FailureDetector = {
|
|
|
|
|
|
import remoteSettings.{ WatchFailureDetectorImplementationClass ⇒ fqcn }
|
|
|
|
|
|
system.dynamicAccess.createInstanceFor[FailureDetector](
|
|
|
|
|
|
fqcn, List(classOf[Config] -> remoteSettings.WatchFailureDetectorConfig)).recover({
|
|
|
|
|
|
case e ⇒ throw new ConfigurationException(
|
|
|
|
|
|
s"Could not create custom remote watcher failure detector [$fqcn] due to: ${e.toString}", e)
|
|
|
|
|
|
}).get
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
new DefaultFailureDetectorRegistry(() ⇒ createFailureDetector())
|
2011-11-16 17:18:36 +01:00
|
|
|
|
}
|
2011-09-19 14:43:28 +02:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
protected def createRemoteDeploymentWatcher(system: ActorSystemImpl): ActorRef =
|
|
|
|
|
|
system.systemActorOf(Props[RemoteDeploymentWatcher], "remote-deployment-watcher")
|
|
|
|
|
|
|
2012-01-31 21:19:28 +01:00
|
|
|
|
def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath,
|
2012-06-13 17:57:56 +02:00
|
|
|
|
systemService: Boolean, deploy: Option[Deploy], lookupDeploy: Boolean, async: Boolean): InternalActorRef = {
|
|
|
|
|
|
if (systemService) local.actorOf(system, props, supervisor, path, systemService, deploy, lookupDeploy, async)
|
2011-10-18 14:21:48 +02:00
|
|
|
|
else {
|
2011-12-10 20:32:23 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* This needs to deal with “mangled” paths, which are created by remote
|
|
|
|
|
|
* deployment, also in this method. The scheme is the following:
|
2011-12-14 22:46:43 +01:00
|
|
|
|
*
|
|
|
|
|
|
* Whenever a remote deployment is found, create a path on that remote
|
2011-12-10 20:32:23 +01:00
|
|
|
|
* address below “remote”, including the current system’s identification
|
|
|
|
|
|
* as “sys@host:port” (typically; it will use whatever the remote
|
|
|
|
|
|
* transport uses). This means that on a path up an actor tree each node
|
2012-09-12 11:18:42 +02:00
|
|
|
|
* change introduces one layer or “remote/scheme/sys@host:port/” within the URI.
|
2011-12-14 22:46:43 +01:00
|
|
|
|
*
|
2011-12-10 20:32:23 +01:00
|
|
|
|
* Example:
|
2011-12-14 22:46:43 +01:00
|
|
|
|
*
|
2012-09-12 11:18:42 +02:00
|
|
|
|
* akka://sys@home:1234/remote/akka/sys@remote:6667/remote/akka/sys@other:3333/user/a/b/c
|
2011-12-14 22:46:43 +01:00
|
|
|
|
*
|
2012-09-12 11:18:42 +02:00
|
|
|
|
* means that the logical parent originates from “akka://sys@other:3333” with
|
|
|
|
|
|
* one child (may be “a” or “b”) being deployed on “akka://sys@remote:6667” and
|
|
|
|
|
|
* finally either “b” or “c” being created on “akka://sys@home:1234”, where
|
2011-12-14 22:46:43 +01:00
|
|
|
|
* this whole thing actually resides. Thus, the logical path is
|
|
|
|
|
|
* “/user/a/b/c” and the physical path contains all remote placement
|
2011-12-10 20:32:23 +01:00
|
|
|
|
* information.
|
2011-12-14 22:46:43 +01:00
|
|
|
|
*
|
2011-12-10 20:32:23 +01:00
|
|
|
|
* Deployments are always looked up using the logical path, which is the
|
|
|
|
|
|
* purpose of the lookupRemotes internal method.
|
|
|
|
|
|
*/
|
2011-10-18 11:26:35 +02:00
|
|
|
|
|
2011-12-09 18:07:42 +01:00
|
|
|
|
@scala.annotation.tailrec
|
2011-12-12 23:31:15 +01:00
|
|
|
|
def lookupRemotes(p: Iterable[String]): Option[Deploy] = {
|
2011-12-09 18:07:42 +01:00
|
|
|
|
p.headOption match {
|
|
|
|
|
|
case None ⇒ None
|
2012-09-12 11:18:42 +02:00
|
|
|
|
case Some("remote") ⇒ lookupRemotes(p.drop(3))
|
2012-04-27 12:48:22 +02:00
|
|
|
|
case Some("user") ⇒ deployer.lookup(p.drop(1))
|
2011-12-09 18:15:14 +01:00
|
|
|
|
case Some(_) ⇒ None
|
2011-12-09 18:07:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-09 18:15:14 +01:00
|
|
|
|
val elems = path.elements
|
2012-01-31 21:19:28 +01:00
|
|
|
|
val lookup =
|
|
|
|
|
|
if (lookupDeploy)
|
|
|
|
|
|
elems.head match {
|
2012-04-27 12:48:22 +02:00
|
|
|
|
case "user" ⇒ deployer.lookup(elems.drop(1))
|
2012-01-31 21:19:28 +01:00
|
|
|
|
case "remote" ⇒ lookupRemotes(elems)
|
|
|
|
|
|
case _ ⇒ None
|
|
|
|
|
|
}
|
|
|
|
|
|
else None
|
|
|
|
|
|
|
|
|
|
|
|
val deployment = {
|
2012-02-03 09:43:23 +01:00
|
|
|
|
deploy.toList ::: lookup.toList match {
|
2012-01-31 21:19:28 +01:00
|
|
|
|
case Nil ⇒ Nil
|
2012-02-03 09:43:23 +01:00
|
|
|
|
case l ⇒ List(l reduce ((a, b) ⇒ b withFallback a))
|
2012-01-31 21:19:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-02-03 09:43:23 +01:00
|
|
|
|
Iterator(props.deploy) ++ deployment.iterator reduce ((a, b) ⇒ b withFallback a) match {
|
2013-04-05 16:12:45 +02:00
|
|
|
|
case d @ Deploy(_, _, _, RemoteScope(addr), _) ⇒
|
2012-12-07 16:03:04 +01:00
|
|
|
|
if (hasAddress(addr)) {
|
2012-06-13 17:57:56 +02:00
|
|
|
|
local.actorOf(system, props, supervisor, path, false, deployment.headOption, false, async)
|
2012-01-31 21:19:28 +01:00
|
|
|
|
} else {
|
2012-11-23 10:15:19 +01:00
|
|
|
|
try {
|
|
|
|
|
|
val localAddress = transport.localAddressForRemote(addr)
|
2013-03-13 16:01:57 +01:00
|
|
|
|
val rpath = (RootActorPath(addr) / "remote" / localAddress.protocol / localAddress.hostPort / path.elements).
|
|
|
|
|
|
withUid(path.uid)
|
2013-03-06 15:10:59 +01:00
|
|
|
|
new RemoteActorRef(transport, localAddress, rpath, supervisor, Some(props), Some(d))
|
2012-11-23 10:15:19 +01:00
|
|
|
|
} catch {
|
|
|
|
|
|
case NonFatal(e) ⇒
|
2013-03-26 18:17:50 +01:00
|
|
|
|
log.error(e, "Error while looking up address [{}]", addr)
|
2012-11-23 10:15:19 +01:00
|
|
|
|
new EmptyLocalActorRef(this, path, eventStream)
|
|
|
|
|
|
}
|
2011-12-09 00:02:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-13 17:57:56 +02:00
|
|
|
|
case _ ⇒ local.actorOf(system, props, supervisor, path, systemService, deployment.headOption, false, async)
|
2011-09-27 16:52:33 +02:00
|
|
|
|
}
|
2011-09-15 10:20:18 +02:00
|
|
|
|
}
|
2011-12-13 10:58:09 +01:00
|
|
|
|
}
|
2011-09-15 10:20:18 +02:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
@deprecated("use actorSelection instead of actorFor", "2.2")
|
2012-11-23 10:15:19 +01:00
|
|
|
|
def actorFor(path: ActorPath): InternalActorRef = {
|
2012-12-07 16:03:04 +01:00
|
|
|
|
if (hasAddress(path.address)) actorFor(rootGuardian, path.elements)
|
2012-11-23 10:15:19 +01:00
|
|
|
|
else try {
|
2013-03-06 15:10:59 +01:00
|
|
|
|
new RemoteActorRef(transport, transport.localAddressForRemote(path.address),
|
2012-11-23 10:15:19 +01:00
|
|
|
|
path, Nobody, props = None, deploy = None)
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
case NonFatal(e) ⇒
|
2013-03-26 18:17:50 +01:00
|
|
|
|
log.error(e, "Error while looking up address [{}]", path.address)
|
2012-11-23 10:15:19 +01:00
|
|
|
|
new EmptyLocalActorRef(this, path, eventStream)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-12-07 16:29:12 +01:00
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
@deprecated("use actorSelection instead of actorFor", "2.2")
|
2011-12-07 16:29:12 +01:00
|
|
|
|
def actorFor(ref: InternalActorRef, path: String): InternalActorRef = path match {
|
2012-01-20 14:29:50 +01:00
|
|
|
|
case ActorPathExtractor(address, elems) ⇒
|
2012-12-07 16:03:04 +01:00
|
|
|
|
if (hasAddress(address)) actorFor(rootGuardian, elems)
|
2013-03-26 11:25:09 +01:00
|
|
|
|
else {
|
|
|
|
|
|
val rootPath = RootActorPath(address) / elems
|
|
|
|
|
|
try {
|
|
|
|
|
|
new RemoteActorRef(transport, transport.localAddressForRemote(address),
|
|
|
|
|
|
rootPath, Nobody, props = None, deploy = None)
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
case NonFatal(e) ⇒
|
2013-03-26 18:17:50 +01:00
|
|
|
|
log.error(e, "Error while looking up address [{}]", rootPath.address)
|
2013-03-26 11:25:09 +01:00
|
|
|
|
new EmptyLocalActorRef(this, rootPath, eventStream)
|
|
|
|
|
|
}
|
2013-03-25 08:42:48 +01:00
|
|
|
|
}
|
2011-12-07 16:29:12 +01:00
|
|
|
|
case _ ⇒ local.actorFor(ref, path)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
@deprecated("use actorSelection instead of actorFor", "2.2")
|
|
|
|
|
|
def actorFor(ref: InternalActorRef, path: Iterable[String]): InternalActorRef =
|
|
|
|
|
|
local.actorFor(ref, path)
|
|
|
|
|
|
|
|
|
|
|
|
def rootGuardianAt(address: Address): ActorRef =
|
|
|
|
|
|
if (hasAddress(address)) rootGuardian
|
|
|
|
|
|
else new RemoteActorRef(transport, transport.localAddressForRemote(address),
|
|
|
|
|
|
RootActorPath(address), Nobody, props = None, deploy = None)
|
|
|
|
|
|
|
2013-02-08 13:13:52 +01:00
|
|
|
|
/**
|
2012-11-21 15:58:01 +01:00
|
|
|
|
* INTERNAL API
|
2013-03-26 18:17:50 +01:00
|
|
|
|
* Called in deserialization of incoming remote messages where the correct local address is known.
|
2012-11-21 15:58:01 +01:00
|
|
|
|
*/
|
2013-03-26 18:17:50 +01:00
|
|
|
|
private[akka] def resolveActorRefWithLocalAddress(path: String, localAddress: Address): InternalActorRef = {
|
2013-03-13 16:01:57 +01:00
|
|
|
|
path match {
|
|
|
|
|
|
case ActorPathExtractor(address, elems) ⇒
|
2013-03-26 18:17:50 +01:00
|
|
|
|
if (hasAddress(address)) local.resolveActorRef(rootGuardian, elems)
|
|
|
|
|
|
else
|
|
|
|
|
|
new RemoteActorRef(transport, localAddress, RootActorPath(address) / elems,
|
|
|
|
|
|
Nobody, props = None, deploy = None)
|
2013-03-13 16:01:57 +01:00
|
|
|
|
case _ ⇒
|
2013-03-26 18:17:50 +01:00
|
|
|
|
log.debug("resolve of unknown path [{}] failed", path)
|
|
|
|
|
|
deadLetters
|
2013-03-13 16:01:57 +01:00
|
|
|
|
}
|
2012-11-21 15:58:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-26 18:17:50 +01:00
|
|
|
|
def resolveActorRef(path: String): ActorRef = path match {
|
|
|
|
|
|
case ActorPathExtractor(address, elems) ⇒
|
|
|
|
|
|
if (hasAddress(address)) local.resolveActorRef(rootGuardian, elems)
|
|
|
|
|
|
else {
|
|
|
|
|
|
val rootPath = RootActorPath(address) / elems
|
|
|
|
|
|
try {
|
|
|
|
|
|
new RemoteActorRef(transport, transport.localAddressForRemote(address),
|
|
|
|
|
|
rootPath, Nobody, props = None, deploy = None)
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
case NonFatal(e) ⇒
|
|
|
|
|
|
log.error(e, "Error while resolving address [{}]", rootPath.address)
|
|
|
|
|
|
new EmptyLocalActorRef(this, rootPath, eventStream)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
case _ ⇒
|
|
|
|
|
|
log.debug("resolve of unknown path [{}] failed", path)
|
|
|
|
|
|
deadLetters
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def resolveActorRef(path: ActorPath): ActorRef = {
|
|
|
|
|
|
if (hasAddress(path.address)) local.resolveActorRef(rootGuardian, path.elements)
|
|
|
|
|
|
else try {
|
|
|
|
|
|
new RemoteActorRef(transport, transport.localAddressForRemote(path.address),
|
|
|
|
|
|
path, Nobody, props = None, deploy = None)
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
case NonFatal(e) ⇒
|
|
|
|
|
|
log.error(e, "Error while resolving address [{}]", path.address)
|
|
|
|
|
|
new EmptyLocalActorRef(this, path, eventStream)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-09-15 10:20:18 +02:00
|
|
|
|
|
2011-09-19 14:43:28 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Using (checking out) actor on a specific node.
|
|
|
|
|
|
*/
|
2013-03-26 18:17:50 +01:00
|
|
|
|
def useActorOnNode(ref: ActorRef, props: Props, deploy: Deploy, supervisor: ActorRef): Unit = {
|
|
|
|
|
|
log.debug("[{}] Instantiating Remote Actor [{}]", rootPath, ref.path)
|
2011-09-19 14:43:28 +02:00
|
|
|
|
|
2011-12-09 00:02:27 +01:00
|
|
|
|
// we don’t wait for the ACK, because the remote end will process this command before any other message to the new actor
|
2013-03-26 18:17:50 +01:00
|
|
|
|
// actorSelection can't be used here because then it is not guaranteed that the actor is created
|
|
|
|
|
|
// before someone can send messages to it
|
|
|
|
|
|
resolveActorRef(RootActorPath(ref.path.address) / "remote") !
|
|
|
|
|
|
DaemonMsgCreate(props, deploy, ref.path.toSerializationFormat, supervisor)
|
2013-04-15 09:26:51 +02:00
|
|
|
|
|
|
|
|
|
|
remoteDeploymentWatcher ! RemoteDeploymentWatcher.WatchRemote(ref, supervisor)
|
2011-09-15 10:20:18 +02:00
|
|
|
|
}
|
2012-02-02 09:40:17 +01:00
|
|
|
|
|
|
|
|
|
|
def getExternalAddressFor(addr: Address): Option[Address] = {
|
|
|
|
|
|
addr match {
|
2012-12-14 13:45:55 +01:00
|
|
|
|
case _ if hasAddress(addr) ⇒ Some(local.rootPath.address)
|
|
|
|
|
|
case Address(_, _, Some(_), Some(_)) ⇒ try Some(transport.localAddressForRemote(addr)) catch { case NonFatal(_) ⇒ None }
|
|
|
|
|
|
case _ ⇒ None
|
2012-02-02 09:40:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-10-26 11:42:18 +02:00
|
|
|
|
|
2012-12-18 16:08:06 +01:00
|
|
|
|
def getDefaultAddress: Address = transport.defaultAddress
|
2012-11-22 14:40:54 +01:00
|
|
|
|
|
2012-12-07 16:03:04 +01:00
|
|
|
|
private def hasAddress(address: Address): Boolean =
|
2012-11-21 11:44:39 +01:00
|
|
|
|
address == local.rootPath.address || address == rootPath.address || transport.addresses(address)
|
2012-10-26 11:42:18 +02:00
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
def quarantine(address: Address, uid: Int): Unit = {
|
|
|
|
|
|
// FIXME send to EndpointManager
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* INTERNAL API
|
|
|
|
|
|
*/
|
|
|
|
|
|
private[akka] def afterSendSystemMessage(message: SystemMessage): Unit =
|
|
|
|
|
|
message match {
|
|
|
|
|
|
// Sending to local remoteWatcher relies strong delivery guarantees of local send, i.e.
|
|
|
|
|
|
// default dispatcher must not be changed to an implementation that defeats that
|
|
|
|
|
|
case Watch(watchee, watcher) ⇒ remoteWatcher ! RemoteWatcher.WatchRemote(watchee, watcher)
|
|
|
|
|
|
case Unwatch(watchee, watcher) ⇒ remoteWatcher ! RemoteWatcher.UnwatchRemote(watchee, watcher)
|
|
|
|
|
|
case _ ⇒
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-15 10:20:18 +02:00
|
|
|
|
}
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
2012-05-24 11:44:39 +02:00
|
|
|
|
private[akka] trait RemoteRef extends ActorRefScope {
|
2012-05-03 21:14:47 +02:00
|
|
|
|
final def isLocal = false
|
2011-12-29 16:27:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-13 17:42:26 +02:00
|
|
|
|
/**
|
2013-02-08 13:13:52 +01:00
|
|
|
|
* INTERNAL API
|
2011-10-13 17:42:26 +02:00
|
|
|
|
* Remote ActorRef that is used when referencing the Actor on a different node than its "home" node.
|
|
|
|
|
|
* This reference is network-aware (remembers its origin) and immutable.
|
|
|
|
|
|
*/
|
2011-12-07 16:29:12 +01:00
|
|
|
|
private[akka] class RemoteActorRef private[akka] (
|
2012-01-20 14:29:50 +01:00
|
|
|
|
remote: RemoteTransport,
|
2012-09-12 11:18:42 +02:00
|
|
|
|
val localAddressToUse: Address,
|
2011-12-07 16:29:12 +01:00
|
|
|
|
val path: ActorPath,
|
2012-10-15 13:33:39 +02:00
|
|
|
|
val getParent: InternalActorRef,
|
|
|
|
|
|
props: Option[Props],
|
|
|
|
|
|
deploy: Option[Deploy])
|
2011-12-29 16:27:32 +01:00
|
|
|
|
extends InternalActorRef with RemoteRef {
|
2011-11-08 11:56:46 +01:00
|
|
|
|
|
2011-12-09 00:02:27 +01:00
|
|
|
|
def getChild(name: Iterator[String]): InternalActorRef = {
|
2011-12-09 18:07:42 +01:00
|
|
|
|
val s = name.toStream
|
|
|
|
|
|
s.headOption match {
|
|
|
|
|
|
case None ⇒ this
|
|
|
|
|
|
case Some("..") ⇒ getParent getChild name
|
2013-03-06 15:10:59 +01:00
|
|
|
|
case _ ⇒ new RemoteActorRef(remote, localAddressToUse, path / s, Nobody, props = None, deploy = None)
|
2011-12-09 18:07:42 +01:00
|
|
|
|
}
|
2011-12-09 00:02:27 +01:00
|
|
|
|
}
|
2011-12-03 11:06:38 +01:00
|
|
|
|
|
2013-03-31 03:04:12 +02:00
|
|
|
|
@deprecated("Use context.watch(actor) and receive Terminated(actor)", "2.2") override def isTerminated: Boolean = false
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
2013-01-27 12:56:35 +01:00
|
|
|
|
private def handleException: Catcher[Unit] = {
|
|
|
|
|
|
case e: InterruptedException ⇒
|
|
|
|
|
|
remote.system.eventStream.publish(Error(e, path.toString, getClass, "interrupted during message send"))
|
|
|
|
|
|
Thread.currentThread.interrupt()
|
|
|
|
|
|
case NonFatal(e) ⇒
|
|
|
|
|
|
remote.system.eventStream.publish(Error(e, path.toString, getClass, "swallowing exception during message send"))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-04-15 09:26:51 +02:00
|
|
|
|
def sendSystemMessage(message: SystemMessage): Unit =
|
|
|
|
|
|
try {
|
|
|
|
|
|
remote.send(message, None, this)
|
|
|
|
|
|
provider.afterSendSystemMessage(message)
|
|
|
|
|
|
} catch handleException
|
2011-10-18 15:39:26 +02:00
|
|
|
|
|
2013-02-20 11:42:29 +01:00
|
|
|
|
override def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit = {
|
|
|
|
|
|
if (message == null) throw new InvalidMessageException("Message is null")
|
2013-01-27 12:56:35 +01:00
|
|
|
|
try remote.send(message, Option(sender), this) catch handleException
|
2013-02-20 11:42:29 +01:00
|
|
|
|
}
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
2013-03-06 15:10:59 +01:00
|
|
|
|
override def provider: RemoteActorRefProvider = remote.provider
|
|
|
|
|
|
|
|
|
|
|
|
def start(): Unit =
|
2013-03-26 18:17:50 +01:00
|
|
|
|
if (props.isDefined && deploy.isDefined) remote.provider.useActorOnNode(this, props.get, deploy.get, getParent)
|
2012-10-10 14:19:15 +02:00
|
|
|
|
|
2011-12-08 14:44:05 +01:00
|
|
|
|
def suspend(): Unit = sendSystemMessage(Suspend())
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
2012-08-08 14:13:52 +02:00
|
|
|
|
def resume(causedByFailure: Throwable): Unit = sendSystemMessage(Resume(causedByFailure))
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
2011-12-08 14:44:05 +01:00
|
|
|
|
def stop(): Unit = sendSystemMessage(Terminate())
|
|
|
|
|
|
|
|
|
|
|
|
def restart(cause: Throwable): Unit = sendSystemMessage(Recreate(cause))
|
2011-10-13 17:42:26 +02:00
|
|
|
|
|
|
|
|
|
|
@throws(classOf[java.io.ObjectStreamException])
|
2013-03-25 08:42:48 +01:00
|
|
|
|
private def writeReplace(): AnyRef = SerializedActorRef(this)
|
2012-10-15 13:33:39 +02:00
|
|
|
|
}
|