+per #15229 defer for PersistentActor

* Deferred events are not persisted, thus will not participate in replays
  etc. If users want events to be persisted, they can simply use
  `persistAsync` instead.
* This, 3rd, rewrite extends the Persistent hierarchy by a top level
  trait "Resequenceable", which is used to mark every event to be sent
  in sequence back to the PersistentActor. These are split into
  NonPersistentRepr or PersistentRepr, and acted upon accordingly.
* defer is guaranteed to be called, even after persistence failures
* Includes docs updates for java/scala/java8

Resolves #15229
Depends on #15227

Conflicts:
	akka-docs/rst/scala/code/docs/persistence/PersistenceDocSpec.scala
	akka-persistence/src/main/scala/akka/persistence/JournalProtocol.scala
	akka-persistence/src/main/scala/akka/persistence/Processor.scala
	akka-persistence/src/test/scala/akka/persistence/PersistentActorSpec.scala
	project/AkkaBuild.scala
This commit is contained in:
Konrad 'ktoso' Malawski 2014-06-03 16:40:44 +02:00
parent 580b5af816
commit a71790bb18
19 changed files with 905 additions and 159 deletions

View file

@ -18,7 +18,7 @@ object PersistentActorSpec {
final case class Cmd(data: Any)
final case class Evt(data: Any)
abstract class ExampleProcessor(name: String) extends NamedProcessor(name) with PersistentActor {
abstract class ExamplePersistentActor(name: String) extends NamedProcessor(name) with PersistentActor {
var events: List[Any] = Nil
val updateState: Receive = {
@ -33,14 +33,14 @@ object PersistentActorSpec {
def receiveRecover = updateState
}
class Behavior1Processor(name: String) extends ExampleProcessor(name) {
class Behavior1Processor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = commonBehavior orElse {
case Cmd(data)
persist(Seq(Evt(s"${data}-1"), Evt(s"${data}-2")))(updateState)
}
}
class Behavior2Processor(name: String) extends ExampleProcessor(name) {
class Behavior2Processor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = commonBehavior orElse {
case Cmd(data)
persist(Seq(Evt(s"${data}-1"), Evt(s"${data}-2")))(updateState)
@ -48,7 +48,7 @@ object PersistentActorSpec {
}
}
class Behavior3Processor(name: String) extends ExampleProcessor(name) {
class Behavior3Processor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = commonBehavior orElse {
case Cmd(data)
persist(Seq(Evt(s"${data}-11"), Evt(s"${data}-12")))(updateState)
@ -56,7 +56,7 @@ object PersistentActorSpec {
}
}
class ChangeBehaviorInLastEventHandlerProcessor(name: String) extends ExampleProcessor(name) {
class ChangeBehaviorInLastEventHandlerProcessor(name: String) extends ExamplePersistentActor(name) {
val newBehavior: Receive = {
case Cmd(data)
persist(Evt(s"${data}-21"))(updateState)
@ -75,7 +75,7 @@ object PersistentActorSpec {
}
}
class ChangeBehaviorInFirstEventHandlerProcessor(name: String) extends ExampleProcessor(name) {
class ChangeBehaviorInFirstEventHandlerProcessor(name: String) extends ExamplePersistentActor(name) {
val newBehavior: Receive = {
case Cmd(data)
persist(Evt(s"${data}-21")) { event
@ -94,7 +94,7 @@ object PersistentActorSpec {
}
}
class ChangeBehaviorInCommandHandlerFirstProcessor(name: String) extends ExampleProcessor(name) {
class ChangeBehaviorInCommandHandlerFirstProcessor(name: String) extends ExamplePersistentActor(name) {
val newBehavior: Receive = {
case Cmd(data)
context.unbecome()
@ -109,7 +109,7 @@ object PersistentActorSpec {
}
}
class ChangeBehaviorInCommandHandlerLastProcessor(name: String) extends ExampleProcessor(name) {
class ChangeBehaviorInCommandHandlerLastProcessor(name: String) extends ExamplePersistentActor(name) {
val newBehavior: Receive = {
case Cmd(data)
persist(Seq(Evt(s"${data}-31"), Evt(s"${data}-32")))(updateState)
@ -124,7 +124,7 @@ object PersistentActorSpec {
}
}
class SnapshottingPersistentActor(name: String, probe: ActorRef) extends ExampleProcessor(name) {
class SnapshottingPersistentActor(name: String, probe: ActorRef) extends ExamplePersistentActor(name) {
override def receiveRecover = super.receiveRecover orElse {
case SnapshotOffer(_, events: List[_])
probe ! "offered"
@ -160,14 +160,14 @@ object PersistentActorSpec {
}
}
class ReplyInEventHandlerProcessor(name: String) extends ExampleProcessor(name) {
class ReplyInEventHandlerProcessor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd("a") persist(Evt("a"))(evt sender() ! evt.data)
case p: Persistent sender() ! p // not expected
}
}
class UserStashProcessor(name: String) extends ExampleProcessor(name) {
class UserStashProcessor(name: String) extends ExamplePersistentActor(name) {
var stashed = false
val receiveCommand: Receive = {
case Cmd("a") if (!stashed) { stash(); stashed = true } else sender() ! "a"
@ -176,7 +176,7 @@ object PersistentActorSpec {
}
}
class UserStashManyProcessor(name: String) extends ExampleProcessor(name) {
class UserStashManyProcessor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = commonBehavior orElse {
case Cmd("a") persist(Evt("a")) { evt
updateState(evt)
@ -196,7 +196,7 @@ object PersistentActorSpec {
case other stash()
}
}
class AsyncPersistProcessor(name: String) extends ExampleProcessor(name) {
class AsyncPersistProcessor(name: String) extends ExamplePersistentActor(name) {
var counter = 0
val receiveCommand: Receive = commonBehavior orElse {
@ -212,7 +212,7 @@ object PersistentActorSpec {
counter
}
}
class AsyncPersistThreeTimesProcessor(name: String) extends ExampleProcessor(name) {
class AsyncPersistThreeTimesProcessor(name: String) extends ExamplePersistentActor(name) {
var counter = 0
val receiveCommand: Receive = commonBehavior orElse {
@ -231,7 +231,7 @@ object PersistentActorSpec {
counter
}
}
class AsyncPersistSameEventTwiceProcessor(name: String) extends ExampleProcessor(name) {
class AsyncPersistSameEventTwiceProcessor(name: String) extends ExamplePersistentActor(name) {
// atomic because used from inside the *async* callbacks
val sendMsgCounter = new AtomicInteger()
@ -249,7 +249,7 @@ object PersistentActorSpec {
persistAsync(event) { evt sender() ! s"${evt.data}-b-${sendMsgCounter.incrementAndGet()}" }
}
}
class AsyncPersistAndPersistMixedSyncAsyncSyncProcessor(name: String) extends ExampleProcessor(name) {
class AsyncPersistAndPersistMixedSyncAsyncSyncProcessor(name: String) extends ExamplePersistentActor(name) {
var counter = 0
@ -276,12 +276,10 @@ object PersistentActorSpec {
counter
}
}
class AsyncPersistAndPersistMixedSyncAsyncProcessor(name: String) extends ExampleProcessor(name) {
class AsyncPersistAndPersistMixedSyncAsyncProcessor(name: String) extends ExamplePersistentActor(name) {
var sendMsgCounter = 0
val start = System.currentTimeMillis()
def time = s" ${System.currentTimeMillis() - start}ms"
val receiveCommand: Receive = commonBehavior orElse {
case Cmd(data)
sender() ! data
@ -301,7 +299,7 @@ object PersistentActorSpec {
}
}
class UserStashFailureProcessor(name: String) extends ExampleProcessor(name) {
class UserStashFailureProcessor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = commonBehavior orElse {
case Cmd(data)
if (data == "b-2") throw new TestException("boom")
@ -322,7 +320,7 @@ object PersistentActorSpec {
}
}
class AnyValEventProcessor(name: String) extends ExampleProcessor(name) {
class AnyValEventProcessor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd("a") persist(5)(evt sender() ! evt)
}
@ -348,6 +346,44 @@ object PersistentActorSpec {
}
}
class DeferringWithPersistActor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd(data)
defer("d-1") { sender() ! _ }
persist(s"$data-2") { sender() ! _ }
defer("d-3") { sender() ! _ }
defer("d-4") { sender() ! _ }
}
}
class DeferringWithAsyncPersistActor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd(data)
defer(s"d-$data-1") { sender() ! _ }
persistAsync(s"pa-$data-2") { sender() ! _ }
defer(s"d-$data-3") { sender() ! _ }
defer(s"d-$data-4") { sender() ! _ }
}
}
class DeferringMixedCallsPPADDPADPersistActor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd(data)
persist(s"p-$data-1") { sender() ! _ }
persistAsync(s"pa-$data-2") { sender() ! _ }
defer(s"d-$data-3") { sender() ! _ }
defer(s"d-$data-4") { sender() ! _ }
persistAsync(s"pa-$data-5") { sender() ! _ }
defer(s"d-$data-6") { sender() ! _ }
}
}
class DeferringWithNoPersistCallsPersistActor(name: String) extends ExamplePersistentActor(name) {
val receiveCommand: Receive = {
case Cmd(data)
defer("d-1") { sender() ! _ }
defer("d-2") { sender() ! _ }
defer("d-3") { sender() ! _ }
}
}
}
abstract class PersistentActorSpec(config: Config) extends AkkaSpec(config) with PersistenceSpec with ImplicitSender {
@ -625,6 +661,71 @@ abstract class PersistentActorSpec(config: Config) extends AkkaSpec(config) with
expectNoMsg(100.millis)
}
"allow deferring handlers in order to provide ordered processing in respect to persist handlers" in {
val processor = namedProcessor[DeferringWithPersistActor]
processor ! Cmd("a")
expectMsg("d-1")
expectMsg("a-2")
expectMsg("d-3")
expectMsg("d-4")
expectNoMsg(100.millis)
}
"allow deferring handlers in order to provide ordered processing in respect to asyncPersist handlers" in {
val processor = namedProcessor[DeferringWithAsyncPersistActor]
processor ! Cmd("a")
expectMsg("d-a-1")
expectMsg("pa-a-2")
expectMsg("d-a-3")
expectMsg("d-a-4")
expectNoMsg(100.millis)
}
"invoke deferred handlers, in presence of mixed a long series persist / persistAsync calls" in {
val processor = namedProcessor[DeferringMixedCallsPPADDPADPersistActor]
val p1, p2 = TestProbe()
processor.tell(Cmd("a"), p1.ref)
processor.tell(Cmd("b"), p2.ref)
p1.expectMsg("p-a-1")
p1.expectMsg("pa-a-2")
p1.expectMsg("d-a-3")
p1.expectMsg("d-a-4")
p1.expectMsg("pa-a-5")
p1.expectMsg("d-a-6")
p2.expectMsg("p-b-1")
p2.expectMsg("pa-b-2")
p2.expectMsg("d-b-3")
p2.expectMsg("d-b-4")
p2.expectMsg("pa-b-5")
p2.expectMsg("d-b-6")
expectNoMsg(100.millis)
}
"invoke deferred handlers right away, if there are no pending persist handlers registered" in {
val processor = namedProcessor[DeferringWithNoPersistCallsPersistActor]
processor ! Cmd("a")
expectMsg("d-1")
expectMsg("d-2")
expectMsg("d-3")
expectNoMsg(100.millis)
}
"invoke deferred handlers, perserving the original sender references" in {
val processor = namedProcessor[DeferringWithAsyncPersistActor]
val p1, p2 = TestProbe()
processor.tell(Cmd("a"), p1.ref)
processor.tell(Cmd("b"), p2.ref)
p1.expectMsg("d-a-1")
p1.expectMsg("pa-a-2")
p1.expectMsg("d-a-3")
p1.expectMsg("d-a-4")
p2.expectMsg("d-b-1")
p2.expectMsg("pa-b-2")
p2.expectMsg("d-b-3")
p2.expectMsg("d-b-4")
expectNoMsg(100.millis)
}
"receive RecoveryFinished if it is handled after all events have been replayed" in {
val processor1 = system.actorOf(Props(classOf[SnapshottingPersistentActor], name, testActor))
processor1 ! Cmd("b")