2013-10-09 13:11:53 +02:00
|
|
|
/**
|
2015-03-07 22:58:48 -08:00
|
|
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
2013-10-09 13:11:53 +02:00
|
|
|
*/
|
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
package docs.persistence
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
import akka.actor.{ Actor, ActorRef, ActorSystem, Props }
|
2015-07-07 16:28:17 +02:00
|
|
|
import akka.pattern.BackoffSupervisor
|
2014-06-24 16:57:33 +02:00
|
|
|
import akka.persistence._
|
|
|
|
|
|
2013-12-06 12:48:44 +01:00
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
import scala.language.postfixOps
|
2015-01-30 18:34:03 +01:00
|
|
|
|
|
|
|
|
object PersistenceDocSpec {
|
|
|
|
|
|
|
|
|
|
trait SomeOtherMessage
|
|
|
|
|
|
|
|
|
|
val persistentActor: ActorRef = ???
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
val config =
|
|
|
|
|
"""
|
|
|
|
|
//#auto-update-interval
|
|
|
|
|
akka.persistence.view.auto-update-interval = 5s
|
|
|
|
|
//#auto-update-interval
|
|
|
|
|
//#auto-update
|
|
|
|
|
akka.persistence.view.auto-update = off
|
|
|
|
|
//#auto-update
|
|
|
|
|
"""
|
|
|
|
|
|
2015-06-24 19:58:43 +02:00
|
|
|
object RecoverySample {
|
2014-12-08 11:02:14 +01:00
|
|
|
trait MyPersistentActor1 extends PersistentActor {
|
2015-06-24 19:58:43 +02:00
|
|
|
//#recovery-disabled
|
|
|
|
|
override def recovery = Recovery.none
|
|
|
|
|
//#recovery-disabled
|
2013-09-14 14:19:18 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
trait MyPersistentActor2 extends PersistentActor {
|
2015-06-24 19:58:43 +02:00
|
|
|
//#recovery-custom
|
|
|
|
|
override def recovery = Recovery(toSequenceNr = 457L)
|
|
|
|
|
//#recovery-custom
|
2013-09-14 14:19:18 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
class MyPersistentActor4 extends PersistentActor {
|
2014-06-26 13:56:01 +02:00
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
2014-03-24 15:35:54 +01:00
|
|
|
//#recovery-completed
|
2014-04-09 11:40:31 +02:00
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveRecover: Receive = {
|
|
|
|
|
case RecoveryCompleted =>
|
|
|
|
|
// perform init after recovery, before any other messages
|
|
|
|
|
//...
|
2014-07-08 18:30:15 +02:00
|
|
|
case evt => //...
|
2014-06-25 12:51:21 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveCommand: Receive = {
|
2014-07-08 18:30:15 +02:00
|
|
|
case msg => //...
|
2014-03-24 15:35:54 +01:00
|
|
|
}
|
|
|
|
|
//#recovery-completed
|
|
|
|
|
}
|
2013-09-14 14:19:18 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object PersistenceId {
|
2014-12-08 11:02:14 +01:00
|
|
|
trait PersistentActorMethods {
|
2014-06-23 14:33:35 +02:00
|
|
|
//#persistence-id
|
|
|
|
|
def persistenceId: String
|
|
|
|
|
//#persistence-id
|
2013-09-14 14:19:18 +02:00
|
|
|
//#recovery-status
|
|
|
|
|
def recoveryRunning: Boolean
|
|
|
|
|
def recoveryFinished: Boolean
|
|
|
|
|
//#recovery-status
|
|
|
|
|
}
|
2014-12-08 11:02:14 +01:00
|
|
|
class MyPersistentActor1 extends PersistentActor with PersistentActorMethods {
|
2014-06-23 14:33:35 +02:00
|
|
|
//#persistence-id-override
|
|
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
//#persistence-id-override
|
2014-12-08 11:02:14 +01:00
|
|
|
|
|
|
|
|
override def receiveRecover: Receive = {
|
|
|
|
|
case _ =>
|
|
|
|
|
}
|
|
|
|
|
override def receiveCommand: Receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case _ =>
|
2013-09-14 14:19:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 19:03:00 +02:00
|
|
|
object Backoff {
|
|
|
|
|
abstract class MyActor extends Actor {
|
|
|
|
|
import PersistAsync.MyPersistentActor
|
|
|
|
|
//#backoff
|
|
|
|
|
val childProps = Props[MyPersistentActor]
|
|
|
|
|
val props = BackoffSupervisor.props(
|
|
|
|
|
childProps,
|
|
|
|
|
childName = "myActor",
|
|
|
|
|
minBackoff = 3.seconds,
|
|
|
|
|
maxBackoff = 30.seconds,
|
|
|
|
|
randomFactor = 0.2)
|
|
|
|
|
context.actorOf(props, name = "mySupervisor")
|
|
|
|
|
//#backoff
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object AtLeastOnce {
|
2014-06-03 15:10:56 +02:00
|
|
|
//#at-least-once-example
|
2014-08-29 11:17:33 +02:00
|
|
|
import akka.actor.{ Actor, ActorPath }
|
2014-06-03 15:10:56 +02:00
|
|
|
import akka.persistence.AtLeastOnceDelivery
|
|
|
|
|
|
|
|
|
|
case class Msg(deliveryId: Long, s: String)
|
|
|
|
|
case class Confirm(deliveryId: Long)
|
|
|
|
|
|
|
|
|
|
sealed trait Evt
|
|
|
|
|
case class MsgSent(s: String) extends Evt
|
|
|
|
|
case class MsgConfirmed(deliveryId: Long) extends Evt
|
|
|
|
|
|
|
|
|
|
class MyPersistentActor(destination: ActorPath)
|
|
|
|
|
extends PersistentActor with AtLeastOnceDelivery {
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def persistenceId: String = "persistence-id"
|
|
|
|
|
|
|
|
|
|
override def receiveCommand: Receive = {
|
2014-06-03 15:10:56 +02:00
|
|
|
case s: String => persist(MsgSent(s))(updateState)
|
|
|
|
|
case Confirm(deliveryId) => persist(MsgConfirmed(deliveryId))(updateState)
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveRecover: Receive = {
|
2014-06-03 15:10:56 +02:00
|
|
|
case evt: Evt => updateState(evt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def updateState(evt: Evt): Unit = evt match {
|
|
|
|
|
case MsgSent(s) =>
|
|
|
|
|
deliver(destination, deliveryId => Msg(deliveryId, s))
|
|
|
|
|
|
|
|
|
|
case MsgConfirmed(deliveryId) => confirmDelivery(deliveryId)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class MyDestination extends Actor {
|
|
|
|
|
def receive = {
|
|
|
|
|
case Msg(deliveryId, s) =>
|
|
|
|
|
// ...
|
|
|
|
|
sender() ! Confirm(deliveryId)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#at-least-once-example
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object SaveSnapshot {
|
2013-09-14 14:19:18 +02:00
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
class MyPersistentActor extends PersistentActor {
|
|
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
2013-09-26 09:14:43 +02:00
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
//#save-snapshot
|
2013-09-26 09:14:43 +02:00
|
|
|
var state: Any = _
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveCommand: Receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case "snap" => saveSnapshot(state)
|
|
|
|
|
case SaveSnapshotSuccess(metadata) => // ...
|
|
|
|
|
case SaveSnapshotFailure(metadata, reason) => // ...
|
2013-09-26 09:14:43 +02:00
|
|
|
}
|
2014-12-08 11:02:14 +01:00
|
|
|
//#save-snapshot
|
|
|
|
|
|
|
|
|
|
override def receiveRecover: Receive = ???
|
2013-09-26 09:14:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object OfferSnapshot {
|
2014-12-08 11:02:14 +01:00
|
|
|
class MyPersistentActor extends PersistentActor {
|
|
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
2015-07-02 00:44:10 +02:00
|
|
|
//#snapshot-criteria
|
|
|
|
|
override def recovery = Recovery(fromSnapshot = SnapshotSelectionCriteria(
|
|
|
|
|
maxSequenceNr = 457L,
|
|
|
|
|
maxTimestamp = System.currentTimeMillis))
|
|
|
|
|
//#snapshot-criteria
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
//#snapshot-offer
|
2013-09-26 09:14:43 +02:00
|
|
|
var state: Any = _
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveRecover: Receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case SnapshotOffer(metadata, offeredSnapshot) => state = offeredSnapshot
|
2014-12-08 11:02:14 +01:00
|
|
|
case RecoveryCompleted =>
|
|
|
|
|
case event => // ...
|
2013-09-26 09:14:43 +02:00
|
|
|
}
|
2014-12-08 11:02:14 +01:00
|
|
|
//#snapshot-offer
|
|
|
|
|
|
|
|
|
|
override def receiveCommand: Receive = ???
|
2013-09-26 09:14:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2013-10-27 08:01:14 +01:00
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object PersistAsync {
|
2014-05-21 01:35:21 +02:00
|
|
|
|
|
|
|
|
//#persist-async
|
|
|
|
|
class MyPersistentActor extends PersistentActor {
|
|
|
|
|
|
2014-06-26 13:56:01 +02:00
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveRecover: Receive = {
|
2014-05-21 01:35:21 +02:00
|
|
|
case _ => // handle recovery here
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveCommand: Receive = {
|
2014-05-21 01:35:21 +02:00
|
|
|
case c: String => {
|
|
|
|
|
sender() ! c
|
|
|
|
|
persistAsync(s"evt-$c-1") { e => sender() ! e }
|
|
|
|
|
persistAsync(s"evt-$c-2") { e => sender() ! e }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// usage
|
2014-12-08 11:02:14 +01:00
|
|
|
persistentActor ! "a"
|
|
|
|
|
persistentActor ! "b"
|
2014-05-21 01:35:21 +02:00
|
|
|
|
|
|
|
|
// possible order of received messages:
|
|
|
|
|
// a
|
|
|
|
|
// b
|
|
|
|
|
// evt-a-1
|
|
|
|
|
// evt-a-2
|
|
|
|
|
// evt-b-1
|
|
|
|
|
// evt-b-2
|
|
|
|
|
|
|
|
|
|
//#persist-async
|
|
|
|
|
}
|
2014-06-03 16:40:44 +02:00
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object Defer {
|
2014-06-03 16:40:44 +02:00
|
|
|
|
|
|
|
|
//#defer
|
|
|
|
|
class MyPersistentActor extends PersistentActor {
|
|
|
|
|
|
2014-06-26 13:56:01 +02:00
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveRecover: Receive = {
|
2014-06-03 16:40:44 +02:00
|
|
|
case _ => // handle recovery here
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
override def receiveCommand: Receive = {
|
2014-06-03 16:40:44 +02:00
|
|
|
case c: String => {
|
|
|
|
|
sender() ! c
|
|
|
|
|
persistAsync(s"evt-$c-1") { e => sender() ! e }
|
|
|
|
|
persistAsync(s"evt-$c-2") { e => sender() ! e }
|
2015-05-28 01:37:38 +02:00
|
|
|
deferAsync(s"evt-$c-3") { e => sender() ! e }
|
2014-06-03 16:40:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#defer
|
|
|
|
|
|
|
|
|
|
//#defer-caller
|
2014-12-08 11:02:14 +01:00
|
|
|
persistentActor ! "a"
|
|
|
|
|
persistentActor ! "b"
|
2014-06-03 16:40:44 +02:00
|
|
|
|
|
|
|
|
// order of received messages:
|
|
|
|
|
// a
|
|
|
|
|
// b
|
|
|
|
|
// evt-a-1
|
|
|
|
|
// evt-a-2
|
|
|
|
|
// evt-a-3
|
|
|
|
|
// evt-b-1
|
|
|
|
|
// evt-b-2
|
|
|
|
|
// evt-b-3
|
|
|
|
|
|
|
|
|
|
//#defer-caller
|
|
|
|
|
}
|
2015-01-30 18:34:03 +01:00
|
|
|
|
2015-06-24 19:58:43 +02:00
|
|
|
object NestedPersists {
|
|
|
|
|
|
|
|
|
|
class MyPersistentActor extends PersistentActor {
|
|
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
|
|
|
|
override def receiveRecover: Receive = {
|
|
|
|
|
case _ => // handle recovery here
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#nested-persist-persist
|
|
|
|
|
override def receiveCommand: Receive = {
|
|
|
|
|
case c: String =>
|
|
|
|
|
sender() ! c
|
|
|
|
|
|
|
|
|
|
persist(s"$c-1-outer") { outer1 =>
|
|
|
|
|
sender() ! outer1
|
|
|
|
|
persist(s"$c-1-inner") { inner1 =>
|
|
|
|
|
sender() ! inner1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
persist(s"$c-2-outer") { outer2 =>
|
|
|
|
|
sender() ! outer2
|
|
|
|
|
persist(s"$c-2-inner") { inner2 =>
|
|
|
|
|
sender() ! inner2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#nested-persist-persist
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#nested-persist-persist-caller
|
|
|
|
|
persistentActor ! "a"
|
|
|
|
|
persistentActor ! "b"
|
|
|
|
|
|
|
|
|
|
// order of received messages:
|
|
|
|
|
// a
|
|
|
|
|
// a-outer-1
|
|
|
|
|
// a-outer-2
|
|
|
|
|
// a-inner-1
|
|
|
|
|
// a-inner-2
|
|
|
|
|
// and only then process "b"
|
|
|
|
|
// b
|
|
|
|
|
// b-outer-1
|
|
|
|
|
// b-outer-2
|
|
|
|
|
// b-inner-1
|
|
|
|
|
// b-inner-2
|
|
|
|
|
|
|
|
|
|
//#nested-persist-persist-caller
|
|
|
|
|
|
|
|
|
|
class MyPersistAsyncActor extends PersistentActor {
|
|
|
|
|
override def persistenceId = "my-stable-persistence-id"
|
|
|
|
|
|
|
|
|
|
override def receiveRecover: Receive = {
|
|
|
|
|
case _ => // handle recovery here
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#nested-persistAsync-persistAsync
|
|
|
|
|
override def receiveCommand: Receive = {
|
|
|
|
|
case c: String =>
|
|
|
|
|
sender() ! c
|
|
|
|
|
persistAsync(c + "-outer-1") { outer ⇒
|
|
|
|
|
sender() ! outer
|
|
|
|
|
persistAsync(c + "-inner-1") { inner ⇒ sender() ! inner }
|
|
|
|
|
}
|
|
|
|
|
persistAsync(c + "-outer-2") { outer ⇒
|
|
|
|
|
sender() ! outer
|
|
|
|
|
persistAsync(c + "-inner-2") { inner ⇒ sender() ! inner }
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-24 19:58:43 +02:00
|
|
|
//#nested-persistAsync-persistAsync
|
2015-06-24 19:58:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#nested-persistAsync-persistAsync-caller
|
|
|
|
|
persistentActor ! "a"
|
|
|
|
|
persistentActor ! "b"
|
|
|
|
|
|
|
|
|
|
// order of received messages:
|
|
|
|
|
// a
|
|
|
|
|
// b
|
|
|
|
|
// a-outer-1
|
|
|
|
|
// a-outer-2
|
|
|
|
|
// b-outer-1
|
|
|
|
|
// b-outer-2
|
|
|
|
|
// a-inner-1
|
|
|
|
|
// a-inner-2
|
|
|
|
|
// b-inner-1
|
|
|
|
|
// b-inner-2
|
|
|
|
|
|
|
|
|
|
// which can be seen as the following causal relationship:
|
|
|
|
|
// a -> a-outer-1 -> a-outer-2 -> a-inner-1 -> a-inner-2
|
|
|
|
|
// b -> b-outer-1 -> b-outer-2 -> b-inner-1 -> b-inner-2
|
|
|
|
|
|
|
|
|
|
//#nested-persistAsync-persistAsync-caller
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
object View {
|
2014-01-17 06:58:25 +01:00
|
|
|
import akka.actor.Props
|
|
|
|
|
|
2015-01-30 18:34:03 +01:00
|
|
|
val system: ActorSystem = ???
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
//#view
|
2014-06-24 16:57:33 +02:00
|
|
|
class MyView extends PersistentView {
|
2014-06-23 14:33:35 +02:00
|
|
|
override def persistenceId: String = "some-persistence-id"
|
2014-06-24 16:57:33 +02:00
|
|
|
override def viewId: String = "some-persistence-id-view"
|
2014-01-17 06:58:25 +01:00
|
|
|
|
2014-12-08 11:02:14 +01:00
|
|
|
def receive: Receive = {
|
2014-06-24 16:57:33 +02:00
|
|
|
case payload if isPersistent =>
|
|
|
|
|
// handle message from journal...
|
|
|
|
|
case payload =>
|
|
|
|
|
// handle message from user-land...
|
2014-01-17 06:58:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#view
|
|
|
|
|
|
|
|
|
|
//#view-update
|
|
|
|
|
val view = system.actorOf(Props[MyView])
|
|
|
|
|
view ! Update(await = true)
|
|
|
|
|
//#view-update
|
|
|
|
|
}
|
2014-06-03 16:40:44 +02:00
|
|
|
|
2015-06-01 19:03:00 +02:00
|
|
|
}
|