2011-12-21 21:32:20 +13:00
|
|
|
/**
|
2013-01-09 01:47:48 +01:00
|
|
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
2011-12-21 21:32:20 +13:00
|
|
|
*/
|
|
|
|
|
|
2012-05-22 11:37:09 +02:00
|
|
|
package docs.transactor
|
2011-12-21 21:32:20 +13:00
|
|
|
|
2012-06-28 15:33:49 +02:00
|
|
|
import language.postfixOps
|
|
|
|
|
|
2011-12-21 21:32:20 +13:00
|
|
|
import akka.actor._
|
|
|
|
|
import akka.transactor._
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-21 21:32:20 +13:00
|
|
|
import akka.util.Timeout
|
|
|
|
|
import akka.testkit._
|
|
|
|
|
import scala.concurrent.stm._
|
|
|
|
|
|
|
|
|
|
object CoordinatedExample {
|
|
|
|
|
//#coordinated-example
|
|
|
|
|
import akka.actor._
|
|
|
|
|
import akka.transactor._
|
|
|
|
|
import scala.concurrent.stm._
|
|
|
|
|
|
|
|
|
|
case class Increment(friend: Option[ActorRef] = None)
|
|
|
|
|
case object GetCount
|
|
|
|
|
|
|
|
|
|
class Counter extends Actor {
|
|
|
|
|
val count = Ref(0)
|
|
|
|
|
|
|
|
|
|
def receive = {
|
|
|
|
|
case coordinated @ Coordinated(Increment(friend)) ⇒ {
|
|
|
|
|
friend foreach (_ ! coordinated(Increment()))
|
|
|
|
|
coordinated atomic { implicit t ⇒
|
|
|
|
|
count transform (_ + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case GetCount ⇒ sender ! count.single.get
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#coordinated-example
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object CoordinatedApi {
|
|
|
|
|
case object Message
|
|
|
|
|
|
|
|
|
|
class Coordinator extends Actor {
|
|
|
|
|
//#receive-coordinated
|
|
|
|
|
def receive = {
|
|
|
|
|
case coordinated @ Coordinated(Message) ⇒ {
|
|
|
|
|
//#coordinated-atomic
|
|
|
|
|
coordinated atomic { implicit t ⇒
|
|
|
|
|
// do something in the coordinated transaction ...
|
|
|
|
|
}
|
|
|
|
|
//#coordinated-atomic
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#receive-coordinated
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object CounterExample {
|
|
|
|
|
//#counter-example
|
|
|
|
|
import akka.transactor._
|
|
|
|
|
import scala.concurrent.stm._
|
|
|
|
|
|
|
|
|
|
case object Increment
|
|
|
|
|
|
|
|
|
|
class Counter extends Transactor {
|
|
|
|
|
val count = Ref(0)
|
|
|
|
|
|
|
|
|
|
def atomically = implicit txn ⇒ {
|
|
|
|
|
case Increment ⇒ count transform (_ + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#counter-example
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object FriendlyCounterExample {
|
|
|
|
|
//#friendly-counter-example
|
|
|
|
|
import akka.actor._
|
|
|
|
|
import akka.transactor._
|
|
|
|
|
import scala.concurrent.stm._
|
|
|
|
|
|
|
|
|
|
case object Increment
|
|
|
|
|
|
|
|
|
|
class FriendlyCounter(friend: ActorRef) extends Transactor {
|
|
|
|
|
val count = Ref(0)
|
|
|
|
|
|
|
|
|
|
override def coordinate = {
|
|
|
|
|
case Increment ⇒ include(friend)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def atomically = implicit txn ⇒ {
|
|
|
|
|
case Increment ⇒ count transform (_ + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#friendly-counter-example
|
|
|
|
|
|
|
|
|
|
class Friend extends Transactor {
|
|
|
|
|
val count = Ref(0)
|
|
|
|
|
|
|
|
|
|
def atomically = implicit txn ⇒ {
|
|
|
|
|
case Increment ⇒ count transform (_ + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only checked for compilation
|
|
|
|
|
object TransactorCoordinate {
|
|
|
|
|
case object Message
|
|
|
|
|
case object SomeMessage
|
|
|
|
|
case object SomeOtherMessage
|
|
|
|
|
case object OtherMessage
|
|
|
|
|
case object Message1
|
|
|
|
|
case object Message2
|
|
|
|
|
|
|
|
|
|
class TestCoordinateInclude(actor1: ActorRef, actor2: ActorRef, actor3: ActorRef) extends Transactor {
|
|
|
|
|
//#coordinate-include
|
|
|
|
|
override def coordinate = {
|
|
|
|
|
case Message ⇒ include(actor1, actor2, actor3)
|
|
|
|
|
}
|
|
|
|
|
//#coordinate-include
|
|
|
|
|
|
|
|
|
|
def atomically = txn ⇒ doNothing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TestCoordinateSendTo(someActor: ActorRef, actor1: ActorRef, actor2: ActorRef) extends Transactor {
|
|
|
|
|
//#coordinate-sendto
|
|
|
|
|
override def coordinate = {
|
|
|
|
|
case SomeMessage ⇒ sendTo(someActor -> SomeOtherMessage)
|
|
|
|
|
case OtherMessage ⇒ sendTo(actor1 -> Message1, actor2 -> Message2)
|
|
|
|
|
}
|
|
|
|
|
//#coordinate-sendto
|
|
|
|
|
|
|
|
|
|
def atomically = txn ⇒ doNothing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TransactorDocSpec extends AkkaSpec {
|
|
|
|
|
|
|
|
|
|
"coordinated example" in {
|
|
|
|
|
import CoordinatedExample._
|
|
|
|
|
|
|
|
|
|
//#run-coordinated-example
|
2012-06-29 16:06:26 +02:00
|
|
|
import scala.concurrent.Await
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-21 21:32:20 +13:00
|
|
|
import akka.util.Timeout
|
2012-01-18 10:18:51 +01:00
|
|
|
import akka.pattern.ask
|
2011-12-21 21:32:20 +13:00
|
|
|
|
|
|
|
|
val system = ActorSystem("app")
|
|
|
|
|
|
|
|
|
|
val counter1 = system.actorOf(Props[Counter], name = "counter1")
|
|
|
|
|
val counter2 = system.actorOf(Props[Counter], name = "counter2")
|
|
|
|
|
|
|
|
|
|
implicit val timeout = Timeout(5 seconds)
|
|
|
|
|
|
|
|
|
|
counter1 ! Coordinated(Increment(Some(counter2)))
|
|
|
|
|
|
|
|
|
|
val count = Await.result(counter1 ? GetCount, timeout.duration)
|
|
|
|
|
|
|
|
|
|
// count == 1
|
|
|
|
|
//#run-coordinated-example
|
|
|
|
|
|
|
|
|
|
count must be === 1
|
|
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2011-12-21 21:32:20 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"coordinated api" in {
|
|
|
|
|
import CoordinatedApi._
|
|
|
|
|
|
|
|
|
|
//#implicit-timeout
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-21 21:32:20 +13:00
|
|
|
import akka.util.Timeout
|
|
|
|
|
|
|
|
|
|
implicit val timeout = Timeout(5 seconds)
|
|
|
|
|
//#implicit-timeout
|
|
|
|
|
|
|
|
|
|
//#create-coordinated
|
|
|
|
|
val coordinated = Coordinated()
|
|
|
|
|
//#create-coordinated
|
|
|
|
|
|
|
|
|
|
val system = ActorSystem("coordinated")
|
|
|
|
|
val actor = system.actorOf(Props[Coordinator], name = "coordinator")
|
|
|
|
|
|
|
|
|
|
//#send-coordinated
|
|
|
|
|
actor ! Coordinated(Message)
|
|
|
|
|
//#send-coordinated
|
|
|
|
|
|
|
|
|
|
//#include-coordinated
|
|
|
|
|
actor ! coordinated(Message)
|
|
|
|
|
//#include-coordinated
|
|
|
|
|
|
|
|
|
|
coordinated.await()
|
|
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2011-12-21 21:32:20 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"counter transactor" in {
|
|
|
|
|
import CounterExample._
|
|
|
|
|
|
|
|
|
|
val system = ActorSystem("transactors")
|
|
|
|
|
|
2013-04-14 22:56:41 +02:00
|
|
|
// FIXME, or remove the whole transactor module, srsly
|
2011-12-21 21:32:20 +13:00
|
|
|
lazy val underlyingCounter = new Counter
|
|
|
|
|
val counter = system.actorOf(Props(underlyingCounter), name = "counter")
|
|
|
|
|
val coordinated = Coordinated()(Timeout(5 seconds))
|
|
|
|
|
counter ! coordinated(Increment)
|
|
|
|
|
coordinated.await()
|
|
|
|
|
|
|
|
|
|
underlyingCounter.count.single.get must be === 1
|
|
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2011-12-21 21:32:20 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"friendly counter transactor" in {
|
|
|
|
|
import FriendlyCounterExample._
|
|
|
|
|
|
|
|
|
|
val system = ActorSystem("transactors")
|
|
|
|
|
|
|
|
|
|
lazy val underlyingFriend = new Friend
|
|
|
|
|
val friend = system.actorOf(Props(underlyingFriend), name = "friend")
|
|
|
|
|
|
|
|
|
|
lazy val underlyingFriendlyCounter = new FriendlyCounter(friend)
|
|
|
|
|
val friendlyCounter = system.actorOf(Props(underlyingFriendlyCounter), name = "friendly")
|
|
|
|
|
|
|
|
|
|
val coordinated = Coordinated()(Timeout(5 seconds))
|
|
|
|
|
friendlyCounter ! coordinated(Increment)
|
|
|
|
|
coordinated.await()
|
|
|
|
|
|
|
|
|
|
underlyingFriendlyCounter.count.single.get must be === 1
|
|
|
|
|
underlyingFriend.count.single.get must be === 1
|
|
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2011-12-21 21:32:20 +13:00
|
|
|
}
|
|
|
|
|
}
|