add NullMessage after Supervise to prevent race, see #2418
- parent just checked for system messages and finds none - Supervise is enqueued to parent - Failed is enqueued to the parent - Failed is processed before Supervise and thus dropped due to non-matching UID remedy is to enqueue NullMessage after enqueuing Supervise but before really starting the actor, so that if NullMessage overtakes Supervise the loop in processMailbox will then pick up Supervise next
This commit is contained in:
parent
f7a39d50f4
commit
f0c370cf87
4 changed files with 12 additions and 2 deletions
|
|
@ -5,16 +5,15 @@
|
|||
package akka.actor
|
||||
|
||||
import java.io.{ ObjectOutputStream, NotSerializableException }
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.immutable.TreeSet
|
||||
import scala.concurrent.util.Duration
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
import akka.actor.cell.ChildrenContainer
|
||||
import akka.dispatch.{ Watch, Unwatch, Terminate, SystemMessage, Suspend, Supervise, Resume, Recreate, NoMessage, MessageDispatcher, Envelope, Create, ChildTerminated }
|
||||
import akka.event.Logging.{ LogEvent, Debug, Error }
|
||||
import akka.japi.Procedure
|
||||
import akka.dispatch.NullMessage
|
||||
|
||||
/**
|
||||
* The actor context - the view of the actor cell from the actor.
|
||||
|
|
@ -365,6 +364,7 @@ private[akka] class ActorCell(
|
|||
publish(Debug(self.path.toString, clazz(actor), "received AutoReceiveMessage " + msg))
|
||||
|
||||
msg.message match {
|
||||
case NullMessage ⇒ // do nothing
|
||||
case Failed(cause, uid) ⇒ handleFailure(sender, cause, uid)
|
||||
case t @ Terminated(actor) ⇒
|
||||
getChildByRef(actor) match {
|
||||
|
|
|
|||
|
|
@ -360,6 +360,7 @@ class LocalActorRefProvider(
|
|||
|
||||
override def !(message: Any)(implicit sender: ActorRef = null): Unit = stopped.ifOff(message match {
|
||||
case Failed(ex, _) if sender ne null ⇒ causeOfTermination = Some(ex); sender.asInstanceOf[InternalActorRef].stop()
|
||||
case NullMessage ⇒ // do nothing
|
||||
case _ ⇒ log.error(this + " received unexpected message [" + message + "]")
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import akka.dispatch.{ Terminate, SystemMessage, Suspend, Resume, Recreate, Mess
|
|||
import akka.event.Logging.Error
|
||||
import akka.util.Unsafe
|
||||
import scala.util.control.NonFatal
|
||||
import akka.dispatch.NullMessage
|
||||
|
||||
private[akka] trait Dispatch { this: ActorCell ⇒
|
||||
|
||||
|
|
@ -56,6 +57,7 @@ private[akka] trait Dispatch { this: ActorCell ⇒
|
|||
if (sendSupervise) {
|
||||
// ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅
|
||||
parent.sendSystemMessage(akka.dispatch.Supervise(self, uid))
|
||||
parent.tell(NullMessage)
|
||||
}
|
||||
|
||||
// This call is expected to start off the actor by scheduling its mailbox.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ object Envelope {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This message is sent directly after the Supervise system message in order
|
||||
* to form a barrier wrt. the first real message sent by the child, so that e.g.
|
||||
* Failed() cannot overtake Supervise(). Processing this does nothing.
|
||||
*/
|
||||
case object NullMessage extends AutoReceivedMessage
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue