alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Akka/Scala example source code file (UidClashTest.scala)

This example Akka source code file (UidClashTest.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Akka and Scala source code examples by using tags.

All credit for the original source code belongs to akka.io; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Akka tags/keywords

actor, actorref, akka, dispatch, pingmyself, pleaserestart, restartedsafely, terminated, terminatedfornonwatchedactor, test, testing, testkit, throwable, uidclashtest, unit, utilities

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 examples

Here 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

 

new blog posts

 

Copyright 1998-2021 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.