pekko/akka-docs/src/test/scala/docs/actor/SharedMutableStateDocSpec.scala

79 lines
2.2 KiB
Scala
Raw Normal View History

/**
* Copyright (C) 2009-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package docs.actor
class SharedMutableStateDocSpec {
//#mutable-state
import akka.actor.{ Actor, ActorRef }
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.collection.mutable
case class Message(msg: String)
class EchoActor extends Actor {
def receive = {
2017-10-06 10:30:28 +02:00
case msg sender() ! msg
}
}
class CleanUpActor extends Actor {
def receive = {
2017-10-06 10:30:28 +02:00
case set: mutable.Set[_] set.clear()
}
}
class MyActor(echoActor: ActorRef, cleanUpActor: ActorRef) extends Actor {
var state = ""
val mySet = mutable.Set[String]()
def expensiveCalculation(actorRef: ActorRef): String = {
// this is a very costly operation
"Meaning of life is 42"
}
def expensiveCalculation(): String = {
// this is a very costly operation
"Meaning of life is 42"
}
def receive = {
2017-10-06 10:30:28 +02:00
case _
implicit val ec = context.dispatcher
implicit val timeout = Timeout(5 seconds) // needed for `?` below
// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
Future { state = "This will race" }
((echoActor ? Message("With this other one")).mapTo[Message])
2017-10-06 10:30:28 +02:00
.foreach { received state = received.msg }
// Very bad: shared mutable object allows
// the other actor to mutate your own state,
// or worse, you might get weird race conditions
cleanUpActor ! mySet
// Very bad: "sender" changes for every message,
// shared mutable state bug
Future { expensiveCalculation(sender()) }
// Example of correct approach
// Completely safe: "self" is OK to close over
// and it's an ActorRef, which is thread-safe
Future { expensiveCalculation() } foreach { self ! _ }
// Completely safe: we close over a fixed value
// and it's an ActorRef, which is thread-safe
val currentSender = sender()
Future { expensiveCalculation(currentSender) }
}
}
//#mutable-state
}