- replace ActorRef.stop() by ActorRefFactory.stop(child) everywhere - ActorCell “optimizes” this to remove the child from its childrenRefs in order to allow immediate recycling of the name - the lost soul must have a place, for which the Locker has been created, where Davy Jones will happily rebind the soul to his ship (i.e. set “parent” to the locker to avoid mem leak) and periodically revisit it (.stop(), in case of that being lost in comm failure, similar .watch() to re-check liveness)
257 lines
6 KiB
Scala
257 lines
6 KiB
Scala
package akka.docs.actor
|
|
|
|
//#imports1
|
|
import akka.actor.Actor
|
|
import akka.actor.Props
|
|
import akka.event.Logging
|
|
//#imports1
|
|
|
|
//#imports2
|
|
import akka.actor.ActorSystem
|
|
//#imports2
|
|
|
|
import org.scalatest.{ BeforeAndAfterAll, WordSpec }
|
|
import org.scalatest.matchers.MustMatchers
|
|
import akka.testkit._
|
|
import akka.util.duration._
|
|
|
|
//#my-actor
|
|
class MyActor extends Actor {
|
|
val log = Logging(context.system, this)
|
|
def receive = {
|
|
case "test" ⇒ log.info("received test")
|
|
case _ ⇒ log.info("received unknown message")
|
|
}
|
|
}
|
|
//#my-actor
|
|
|
|
case class DoIt(msg: ImmutableMessage)
|
|
case class Message(s: String)
|
|
|
|
//#context-actorOf
|
|
class FirstActor extends Actor {
|
|
val myActor = context.actorOf(Props[MyActor])
|
|
//#context-actorOf
|
|
//#anonymous-actor
|
|
def receive = {
|
|
case m: DoIt ⇒
|
|
context.actorOf(Props(new Actor {
|
|
def receive = {
|
|
case DoIt(msg) ⇒
|
|
val replyMsg = doSomeDangerousWork(msg)
|
|
sender ! replyMsg
|
|
context.stop(self)
|
|
}
|
|
def doSomeDangerousWork(msg: ImmutableMessage): String = { "done" }
|
|
})) ! m
|
|
|
|
case replyMsg: String ⇒ sender ! replyMsg
|
|
}
|
|
//#anonymous-actor
|
|
}
|
|
|
|
//#system-actorOf
|
|
object Main extends App {
|
|
val system = ActorSystem("MySystem")
|
|
val myActor = system.actorOf(Props[MyActor])
|
|
//#system-actorOf
|
|
}
|
|
|
|
class ReplyException extends Actor {
|
|
def receive = {
|
|
case _ ⇒
|
|
//#reply-exception
|
|
try {
|
|
val result = operation()
|
|
sender ! result
|
|
} catch {
|
|
case e: Exception ⇒
|
|
sender ! akka.actor.Status.Failure(e)
|
|
throw e
|
|
}
|
|
//#reply-exception
|
|
}
|
|
|
|
def operation(): String = { "Hi" }
|
|
|
|
}
|
|
|
|
//#swapper
|
|
case object Swap
|
|
class Swapper extends Actor {
|
|
import context._
|
|
val log = Logging(system, this)
|
|
|
|
def receive = {
|
|
case Swap ⇒
|
|
log.info("Hi")
|
|
become {
|
|
case Swap ⇒
|
|
log.info("Ho")
|
|
unbecome() // resets the latest 'become' (just for fun)
|
|
}
|
|
}
|
|
}
|
|
|
|
object SwapperApp extends App {
|
|
val system = ActorSystem("SwapperSystem")
|
|
val swap = system.actorOf(Props[Swapper])
|
|
swap ! Swap // logs Hi
|
|
swap ! Swap // logs Ho
|
|
swap ! Swap // logs Hi
|
|
swap ! Swap // logs Ho
|
|
swap ! Swap // logs Hi
|
|
swap ! Swap // logs Ho
|
|
}
|
|
//#swapper
|
|
|
|
//#receive-orElse
|
|
import akka.actor.Actor.Receive
|
|
|
|
abstract class GenericActor extends Actor {
|
|
// to be defined in subclassing actor
|
|
def specificMessageHandler: Receive
|
|
|
|
// generic message handler
|
|
def genericMessageHandler: Receive = {
|
|
case event ⇒ printf("generic: %s\n", event)
|
|
}
|
|
|
|
def receive = specificMessageHandler orElse genericMessageHandler
|
|
}
|
|
|
|
class SpecificActor extends GenericActor {
|
|
def specificMessageHandler = {
|
|
case event: MyMsg ⇒ printf("specific: %s\n", event.subject)
|
|
}
|
|
}
|
|
|
|
case class MyMsg(subject: String)
|
|
//#receive-orElse
|
|
|
|
class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
|
|
|
|
"import context" in {
|
|
//#import-context
|
|
class FirstActor extends Actor {
|
|
import context._
|
|
val myActor = actorOf(Props[MyActor])
|
|
def receive = {
|
|
case x ⇒ myActor ! x
|
|
}
|
|
}
|
|
//#import-context
|
|
|
|
val first = system.actorOf(Props(new FirstActor))
|
|
system.stop(first)
|
|
|
|
}
|
|
|
|
"creating actor with AkkaSpec.actorOf" in {
|
|
val myActor = system.actorOf(Props[MyActor])
|
|
|
|
// testing the actor
|
|
|
|
// TODO: convert docs to AkkaSpec(Map(...))
|
|
val filter = EventFilter.custom {
|
|
case e: Logging.Info ⇒ true
|
|
case _ ⇒ false
|
|
}
|
|
system.eventStream.publish(TestEvent.Mute(filter))
|
|
system.eventStream.subscribe(testActor, classOf[Logging.Info])
|
|
|
|
myActor ! "test"
|
|
expectMsgPF(1 second) { case Logging.Info(_, "received test") ⇒ true }
|
|
|
|
myActor ! "unknown"
|
|
expectMsgPF(1 second) { case Logging.Info(_, "received unknown message") ⇒ true }
|
|
|
|
system.eventStream.unsubscribe(testActor)
|
|
system.eventStream.publish(TestEvent.UnMute(filter))
|
|
|
|
system.stop(myActor)
|
|
}
|
|
|
|
"creating actor with constructor" in {
|
|
class MyActor(arg: String) extends Actor {
|
|
def receive = { case _ ⇒ () }
|
|
}
|
|
|
|
//#creating-constructor
|
|
// allows passing in arguments to the MyActor constructor
|
|
val myActor = system.actorOf(Props(new MyActor("...")))
|
|
//#creating-constructor
|
|
|
|
system.stop(myActor)
|
|
}
|
|
|
|
"creating actor with Props" in {
|
|
//#creating-props
|
|
import akka.actor.Props
|
|
val dispatcher = system.dispatcherFactory.lookup("my-dispatcher")
|
|
val myActor = system.actorOf(Props[MyActor].withDispatcher(dispatcher), name = "myactor")
|
|
//#creating-props
|
|
|
|
system.stop(myActor)
|
|
}
|
|
|
|
"using ask" in {
|
|
//#using-ask
|
|
class MyActor extends Actor {
|
|
def receive = {
|
|
case x: String ⇒ sender ! x.toUpperCase
|
|
case n: Int ⇒ sender ! (n + 1)
|
|
}
|
|
}
|
|
|
|
val myActor = system.actorOf(Props(new MyActor))
|
|
implicit val timeout = system.settings.ActorTimeout
|
|
val future = myActor ? "hello"
|
|
future.as[String] match {
|
|
case Some(answer) ⇒ //...
|
|
case None ⇒ //...
|
|
}
|
|
val result: Option[Int] = for (x ← (myActor ? 3).as[Int]) yield { 2 * x }
|
|
//#using-ask
|
|
|
|
system.stop(myActor)
|
|
}
|
|
|
|
"using receiveTimeout" in {
|
|
//#receive-timeout
|
|
import akka.actor.ReceiveTimeout
|
|
import akka.util.duration._
|
|
class MyActor extends Actor {
|
|
context.setReceiveTimeout(30 milliseconds)
|
|
def receive = {
|
|
case "Hello" ⇒ //...
|
|
case ReceiveTimeout ⇒ throw new RuntimeException("received timeout")
|
|
}
|
|
}
|
|
//#receive-timeout
|
|
}
|
|
|
|
"using hot-swap" in {
|
|
//#hot-swap-actor
|
|
class HotSwapActor extends Actor {
|
|
import context._
|
|
def angry: Receive = {
|
|
case "foo" ⇒ sender ! "I am already angry?"
|
|
case "bar" ⇒ become(happy)
|
|
}
|
|
|
|
def happy: Receive = {
|
|
case "bar" ⇒ sender ! "I am already happy :-)"
|
|
case "foo" ⇒ become(angry)
|
|
}
|
|
|
|
def receive = {
|
|
case "foo" ⇒ become(angry)
|
|
case "bar" ⇒ become(happy)
|
|
}
|
|
}
|
|
//#hot-swap-actor
|
|
|
|
val actor = system.actorOf(Props(new HotSwapActor))
|
|
}
|
|
}
|