2011-12-19 11:07:59 +01:00
|
|
|
|
/**
|
2015-03-07 22:58:48 -08:00
|
|
|
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
2011-12-19 11:07:59 +01:00
|
|
|
|
*/
|
2012-05-22 11:37:09 +02:00
|
|
|
|
package docs.actor
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
2012-06-28 15:33:49 +02:00
|
|
|
|
import language.postfixOps
|
2015-03-25 20:22:12 +01:00
|
|
|
|
import akka.actor.{ ActorSystem, ActorRef, Props, Terminated }
|
|
|
|
|
|
import FaultHandlingDocSpec._
|
2012-06-28 15:33:49 +02:00
|
|
|
|
|
2011-12-15 21:04:19 +01:00
|
|
|
|
//#testkit
|
2014-12-22 19:55:05 -08:00
|
|
|
|
import com.typesafe.config.{ Config, ConfigFactory }
|
2015-03-25 20:22:12 +01:00
|
|
|
|
import org.scalatest.{ FlatSpecLike, Matchers, BeforeAndAfterAll }
|
|
|
|
|
|
import akka.testkit.{ TestActors, TestKit, ImplicitSender, EventFilter }
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
|
|
|
|
|
//#testkit
|
|
|
|
|
|
object FaultHandlingDocSpec {
|
|
|
|
|
|
//#supervisor
|
|
|
|
|
|
//#child
|
|
|
|
|
|
import akka.actor.Actor
|
|
|
|
|
|
|
|
|
|
|
|
//#child
|
|
|
|
|
|
class Supervisor extends Actor {
|
2012-01-23 13:49:19 +01:00
|
|
|
|
//#strategy
|
|
|
|
|
|
import akka.actor.OneForOneStrategy
|
2012-01-23 17:18:49 +01:00
|
|
|
|
import akka.actor.SupervisorStrategy._
|
2012-09-21 14:50:06 +02:00
|
|
|
|
import scala.concurrent.duration._
|
2012-01-23 13:49:19 +01:00
|
|
|
|
|
2012-10-01 20:35:19 +02:00
|
|
|
|
override val supervisorStrategy =
|
|
|
|
|
|
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
|
2013-12-03 16:34:26 +01:00
|
|
|
|
case _: ArithmeticException => Resume
|
|
|
|
|
|
case _: NullPointerException => Restart
|
|
|
|
|
|
case _: IllegalArgumentException => Stop
|
|
|
|
|
|
case _: Exception => Escalate
|
2012-10-01 20:35:19 +02:00
|
|
|
|
}
|
2012-01-23 13:49:19 +01:00
|
|
|
|
//#strategy
|
|
|
|
|
|
|
2011-12-15 21:04:19 +01:00
|
|
|
|
def receive = {
|
2014-01-16 15:16:35 +01:00
|
|
|
|
case p: Props => sender() ! context.actorOf(p)
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#supervisor
|
|
|
|
|
|
|
|
|
|
|
|
//#supervisor2
|
|
|
|
|
|
class Supervisor2 extends Actor {
|
2012-01-23 13:49:19 +01:00
|
|
|
|
//#strategy2
|
|
|
|
|
|
import akka.actor.OneForOneStrategy
|
2012-01-23 17:18:49 +01:00
|
|
|
|
import akka.actor.SupervisorStrategy._
|
2012-09-21 14:50:06 +02:00
|
|
|
|
import scala.concurrent.duration._
|
2012-01-23 13:49:19 +01:00
|
|
|
|
|
2012-10-01 20:35:19 +02:00
|
|
|
|
override val supervisorStrategy =
|
|
|
|
|
|
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
|
2013-12-03 16:34:26 +01:00
|
|
|
|
case _: ArithmeticException => Resume
|
|
|
|
|
|
case _: NullPointerException => Restart
|
|
|
|
|
|
case _: IllegalArgumentException => Stop
|
|
|
|
|
|
case _: Exception => Escalate
|
2012-10-01 20:35:19 +02:00
|
|
|
|
}
|
2012-01-23 13:49:19 +01:00
|
|
|
|
//#strategy2
|
|
|
|
|
|
|
2011-12-15 21:04:19 +01:00
|
|
|
|
def receive = {
|
2014-01-16 15:16:35 +01:00
|
|
|
|
case p: Props => sender() ! context.actorOf(p)
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
// override default to kill all children during restart
|
|
|
|
|
|
override def preRestart(cause: Throwable, msg: Option[Any]) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#supervisor2
|
|
|
|
|
|
|
2013-08-16 16:47:10 +02:00
|
|
|
|
class Supervisor3 extends Actor {
|
|
|
|
|
|
//#default-strategy-fallback
|
|
|
|
|
|
import akka.actor.OneForOneStrategy
|
|
|
|
|
|
import akka.actor.SupervisorStrategy._
|
|
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
|
|
|
|
|
|
|
override val supervisorStrategy =
|
|
|
|
|
|
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
|
2013-12-03 16:34:26 +01:00
|
|
|
|
case _: ArithmeticException => Resume
|
|
|
|
|
|
case t =>
|
|
|
|
|
|
super.supervisorStrategy.decider.applyOrElse(t, (_: Any) => Escalate)
|
2013-08-16 16:47:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
//#default-strategy-fallback
|
|
|
|
|
|
|
|
|
|
|
|
def receive = Actor.emptyBehavior
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-15 21:04:19 +01:00
|
|
|
|
//#child
|
|
|
|
|
|
class Child extends Actor {
|
|
|
|
|
|
var state = 0
|
|
|
|
|
|
def receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
|
case ex: Exception => throw ex
|
|
|
|
|
|
case x: Int => state = x
|
2014-01-16 15:16:35 +01:00
|
|
|
|
case "get" => sender() ! state
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#child
|
2014-12-22 19:55:05 -08:00
|
|
|
|
|
|
|
|
|
|
val testConf: Config = ConfigFactory.parseString("""
|
|
|
|
|
|
akka {
|
|
|
|
|
|
loggers = ["akka.testkit.TestEventListener"]
|
|
|
|
|
|
}
|
|
|
|
|
|
""")
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
//#testkit
|
2015-03-25 20:22:12 +01:00
|
|
|
|
class FaultHandlingDocSpec(_system: ActorSystem) extends TestKit(_system)
|
|
|
|
|
|
with ImplicitSender with FlatSpecLike with Matchers with BeforeAndAfterAll {
|
|
|
|
|
|
|
|
|
|
|
|
def this() = this(ActorSystem("FaultHandlingDocSpec",
|
|
|
|
|
|
ConfigFactory.parseString("""
|
|
|
|
|
|
akka {
|
|
|
|
|
|
loggers = ["akka.testkit.TestEventListener"]
|
|
|
|
|
|
loglevel = "WARNING"
|
|
|
|
|
|
}
|
|
|
|
|
|
""")))
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
2015-03-25 20:22:12 +01:00
|
|
|
|
override def afterAll {
|
|
|
|
|
|
TestKit.shutdownActorSystem(system)
|
2014-12-22 19:55:05 -08:00
|
|
|
|
}
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
2014-12-22 19:55:05 -08:00
|
|
|
|
"A supervisor" must "apply the chosen strategy for its child" in {
|
2015-01-30 18:34:03 +01:00
|
|
|
|
//#testkit
|
2014-12-22 19:55:05 -08:00
|
|
|
|
|
|
|
|
|
|
//#create
|
|
|
|
|
|
val supervisor = system.actorOf(Props[Supervisor], "supervisor")
|
|
|
|
|
|
|
|
|
|
|
|
supervisor ! Props[Child]
|
|
|
|
|
|
val child = expectMsgType[ActorRef] // retrieve answer from TestKit’s testActor
|
|
|
|
|
|
//#create
|
|
|
|
|
|
EventFilter.warning(occurrences = 1) intercept {
|
|
|
|
|
|
//#resume
|
|
|
|
|
|
child ! 42 // set state to 42
|
|
|
|
|
|
child ! "get"
|
|
|
|
|
|
expectMsg(42)
|
|
|
|
|
|
|
|
|
|
|
|
child ! new ArithmeticException // crash it
|
|
|
|
|
|
child ! "get"
|
|
|
|
|
|
expectMsg(42)
|
|
|
|
|
|
//#resume
|
|
|
|
|
|
}
|
|
|
|
|
|
EventFilter[NullPointerException](occurrences = 1) intercept {
|
|
|
|
|
|
//#restart
|
|
|
|
|
|
child ! new NullPointerException // crash it harder
|
|
|
|
|
|
child ! "get"
|
|
|
|
|
|
expectMsg(0)
|
|
|
|
|
|
//#restart
|
|
|
|
|
|
}
|
|
|
|
|
|
EventFilter[IllegalArgumentException](occurrences = 1) intercept {
|
|
|
|
|
|
//#stop
|
|
|
|
|
|
watch(child) // have testActor watch “child”
|
|
|
|
|
|
child ! new IllegalArgumentException // break it
|
|
|
|
|
|
expectMsgPF() { case Terminated(`child`) => () }
|
|
|
|
|
|
//#stop
|
|
|
|
|
|
}
|
|
|
|
|
|
EventFilter[Exception]("CRASH", occurrences = 2) intercept {
|
|
|
|
|
|
//#escalate-kill
|
|
|
|
|
|
supervisor ! Props[Child] // create new child
|
|
|
|
|
|
val child2 = expectMsgType[ActorRef]
|
|
|
|
|
|
watch(child2)
|
|
|
|
|
|
child2 ! "get" // verify it is alive
|
|
|
|
|
|
expectMsg(0)
|
|
|
|
|
|
|
|
|
|
|
|
child2 ! new Exception("CRASH") // escalate failure
|
|
|
|
|
|
expectMsgPF() {
|
|
|
|
|
|
case t @ Terminated(`child2`) if t.existenceConfirmed => ()
|
|
|
|
|
|
}
|
|
|
|
|
|
//#escalate-kill
|
|
|
|
|
|
//#escalate-restart
|
|
|
|
|
|
val supervisor2 = system.actorOf(Props[Supervisor2], "supervisor2")
|
2012-01-23 13:49:19 +01:00
|
|
|
|
|
2014-12-22 19:55:05 -08:00
|
|
|
|
supervisor2 ! Props[Child]
|
|
|
|
|
|
val child3 = expectMsgType[ActorRef]
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
2014-12-22 19:55:05 -08:00
|
|
|
|
child3 ! 23
|
|
|
|
|
|
child3 ! "get"
|
|
|
|
|
|
expectMsg(23)
|
2011-12-15 21:04:19 +01:00
|
|
|
|
|
2014-12-22 19:55:05 -08:00
|
|
|
|
child3 ! new Exception("CRASH")
|
|
|
|
|
|
child3 ! "get"
|
|
|
|
|
|
expectMsg(0)
|
|
|
|
|
|
//#escalate-restart
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
2014-12-22 19:55:05 -08:00
|
|
|
|
//#testkit
|
|
|
|
|
|
// code here
|
2011-12-15 21:04:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-08-22 16:44:35 +02:00
|
|
|
|
//#testkit
|