Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Enforcing ordering of Terminated wrt remote/local #2835

  • Loading branch information...
commit 58324eb2632e39e2d59f8d78f8f29ee75c08447f 1 parent 6924d53
Endre Sándor Varga authored
View
1  akka-actor/src/main/scala/akka/actor/Address.scala
@@ -19,6 +19,7 @@ import scala.collection.immutable
*/
@SerialVersionUID(1L)
final case class Address private (protocol: String, system: String, host: Option[String], port: Option[Int]) {
+ // Please note that local/non-local distinction must be preserved: host.isDefined == !isLocal
def this(protocol: String, system: String) = this(protocol, system, None, None)
def this(protocol: String, system: String, host: String, port: Int) = this(protocol, system, Option(host), Some(port))
View
26 akka-actor/src/main/scala/akka/actor/dungeon/DeathWatch.scala
@@ -4,7 +4,7 @@
package akka.actor.dungeon
-import akka.actor.{ Terminated, InternalActorRef, ActorRef, ActorCell, Actor, Address, AddressTerminated }
+import akka.actor.{ Terminated, InternalActorRef, ActorRef, ActorRefScope, ActorCell, Actor, Address, AddressTerminated }
import akka.dispatch.{ Watch, Unwatch }
import akka.event.Logging.{ Warning, Error, Debug }
import scala.util.control.NonFatal
@@ -51,12 +51,24 @@ private[akka] trait DeathWatch { this: ActorCell ⇒
if (!watchedBy.isEmpty) {
val terminated = Terminated(self)(existenceConfirmed = true, addressTerminated = false)
try {
- watchedBy foreach {
- watcher
- try watcher.tell(terminated, self) catch {
- case NonFatal(t) publish(Error(t, self.path.toString, clazz(actor), "deathwatch"))
- }
- }
+ def sendTerminated(ifLocal: Boolean)(watcher: ActorRef): Unit =
+ if (watcher.asInstanceOf[ActorRefScope].isLocal == ifLocal) watcher.tell(terminated, self)
+
+ /*
+ * It is important to notify the remote watchers first, otherwise RemoteDaemon might shut down, causing
+ * the remoting to shut down as well. At this point Terminated messages to remote watchers are no longer
+ * deliverable.
+ *
+ * The problematic case is:
+ * 1. Terminated is sent to RemoteDaemon
+ * 1a. RemoteDaemon is fast enough to notify the terminator actor in RemoteActorRefProvider
+ * 1b. The terminator is fast enough to enqueue the shutdown command in the remoting
+ * 2. Only at this point is the Terminated (to be sent remotely) enqueued in the mailbox of remoting
+ *
+ * If the remote watchers are notified first, then the mailbox of the Remoting will guarantee the correct order.
+ */
+ watchedBy foreach sendTerminated(ifLocal = false)
+ watchedBy foreach sendTerminated(ifLocal = true)
} finally watchedBy = ActorCell.emptyActorRefSet
}
}
View
6 akka-actor/src/main/scala/akka/actor/dungeon/FaultHandling.scala
@@ -190,7 +190,11 @@ private[akka] trait FaultHandling { this: ActorCell ⇒
private def finishTerminate() {
val a = actor
- // The following order is crucial for things to work properly. Only chnage this if you're very confident and lucky.
+ /* The following order is crucial for things to work properly. Only change this if you're very confident and lucky.
+ *
+ * Please note that if a parent is also a watcher then ChildTerminated and Terminated must be processed in this
+ * specific order.
+ */
try if (a ne null) a.postStop()
finally try dispatcher.detach(this)
finally try parent.sendSystemMessage(ChildTerminated(self))
Please sign in to comment.
Something went wrong with that request. Please try again.