|
Akka/Scala example source code file (UidClashTest.scala)
The UidClashTest.scala Akka example source code/** * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com> */ package akka.actor import akka.testkit.{ TestProbe, AkkaSpec } import akka.actor.SupervisorStrategy.{ Restart, Stop } import akka.dispatch.sysmsg.SystemMessage import akka.event.EventStream import scala.util.control.NoStackTrace object UidClashTest { class TerminatedForNonWatchedActor extends Exception("Received Terminated for actor that was not actually watched") with NoStackTrace @volatile var oldActor: ActorRef = _ class EvilCollidingActorRef(override val provider: ActorRefProvider, override val path: ActorPath, val eventStream: EventStream) extends MinimalActorRef { //Ignore everything override def isTerminated(): Boolean = true override def sendSystemMessage(message: SystemMessage): Unit = () override def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit = () } def createCollidingRef(system: ActorSystem): ActorRef = new EvilCollidingActorRef(system.asInstanceOf[ActorSystemImpl].provider, oldActor.path, system.eventStream) case object PleaseRestart case object PingMyself case object RestartedSafely class RestartedActor extends Actor { def receive = { case PleaseRestart ⇒ throw new Exception("restart") case Terminated(ref) ⇒ throw new TerminatedForNonWatchedActor // This is the tricky part to make this test a positive one (avoid expectNoMsg). // Since anything enqueued in postRestart will arrive before the Terminated // the bug triggers, there needs to be a bounce: // 1. Ping is sent from postRestart to self // 2. As a response to pint, RestartedSafely is sent to self // 3a. if Terminated was enqueued during the restart procedure it will arrive before the RestartedSafely message // 3b. otherwise only the RestartedSafely message arrives case PingMyself ⇒ self ! RestartedSafely case RestartedSafely ⇒ context.parent ! RestartedSafely } override def preRestart(reason: Throwable, message: Option[Any]): Unit = { context.children foreach { child ⇒ oldActor = child context.unwatch(child) context.stop(child) } } override def preStart(): Unit = context.watch(context.actorOf(Props.empty, "child")) override def postRestart(reason: Throwable): Unit = { context.watch(createCollidingRef(context.system)) self ! PingMyself } // Simulate UID clash } class RestartingActor(probe: ActorRef) extends Actor { override val supervisorStrategy = OneForOneStrategy(loggingEnabled = false) { case _: TerminatedForNonWatchedActor ⇒ context.stop(self) Stop case _ ⇒ Restart } val theRestartedOne = context.actorOf(Props[RestartedActor], "theRestartedOne") def receive = { case PleaseRestart ⇒ theRestartedOne ! PleaseRestart case RestartedSafely ⇒ probe ! RestartedSafely } } } class UidClashTest extends AkkaSpec { import UidClashTest._ "The Terminated message for an old child stopped in preRestart" should { "not arrive after restart" in { val watcher = TestProbe() val topActor = system.actorOf(Props(classOf[RestartingActor], watcher.ref), "top") watcher.watch(topActor) topActor ! PleaseRestart watcher.expectMsg(RestartedSafely) } } } Other Akka source code examplesHere is a short list of links related to this Akka UidClashTest.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.