2013-10-15 09:01:07 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.persistence
|
|
|
|
|
|
|
|
|
|
import java.lang.{ Iterable ⇒ JIterable }
|
|
|
|
|
|
|
|
|
|
import scala.collection.immutable
|
|
|
|
|
|
|
|
|
|
import akka.japi.{ Procedure, Util }
|
|
|
|
|
import akka.persistence.JournalProtocol._
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*
|
|
|
|
|
* Event sourcing mixin for a [[Processor]].
|
|
|
|
|
*/
|
|
|
|
|
private[persistence] trait Eventsourced extends Processor {
|
2013-10-27 08:01:14 +01:00
|
|
|
/**
|
|
|
|
|
* Processor recovery state. Waits for recovery completion and then changes to
|
|
|
|
|
* `processingCommands`
|
|
|
|
|
*/
|
|
|
|
|
private val recovering: State = new State {
|
2013-11-20 13:47:42 +01:00
|
|
|
override def toString: String = "recovering"
|
|
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
def aroundReceive(receive: Receive, message: Any) {
|
|
|
|
|
Eventsourced.super.aroundReceive(receive, message)
|
|
|
|
|
message match {
|
2014-01-17 06:58:25 +01:00
|
|
|
case _: ReadHighestSequenceNrSuccess | _: ReadHighestSequenceNrFailure ⇒
|
|
|
|
|
currentState = processingCommands
|
|
|
|
|
case _ ⇒
|
2013-10-27 08:01:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 09:01:07 +02:00
|
|
|
/**
|
|
|
|
|
* Command processing state. If event persistence is pending after processing a
|
|
|
|
|
* command, event persistence is triggered and state changes to `persistingEvents`.
|
2013-10-27 08:01:14 +01:00
|
|
|
*
|
|
|
|
|
* There's no need to loop commands though the journal any more i.e. they can now be
|
|
|
|
|
* directly offered as `LoopSuccess` to the state machine implemented by `Processor`.
|
2013-10-15 09:01:07 +02:00
|
|
|
*/
|
|
|
|
|
private val processingCommands: State = new State {
|
2013-11-20 13:47:42 +01:00
|
|
|
override def toString: String = "processing commands"
|
|
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
def aroundReceive(receive: Receive, message: Any) {
|
2014-01-17 06:58:25 +01:00
|
|
|
Eventsourced.super.aroundReceive(receive, LoopMessageSuccess(message))
|
2013-10-27 08:01:14 +01:00
|
|
|
if (!persistInvocations.isEmpty) {
|
|
|
|
|
currentState = persistingEvents
|
|
|
|
|
Eventsourced.super.aroundReceive(receive, PersistentBatch(persistentEventBatch.reverse))
|
|
|
|
|
persistInvocations = persistInvocations.reverse
|
|
|
|
|
persistentEventBatch = Nil
|
|
|
|
|
} else {
|
|
|
|
|
processorStash.unstash()
|
2013-10-15 09:01:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Event persisting state. Remains until pending events are persisted and then changes
|
|
|
|
|
* state to `processingCommands`. Only events to be persisted are processed. All other
|
|
|
|
|
* messages are stashed internally.
|
|
|
|
|
*/
|
|
|
|
|
private val persistingEvents: State = new State {
|
2013-11-20 13:47:42 +01:00
|
|
|
override def toString: String = "persisting events"
|
|
|
|
|
|
2013-10-15 09:01:07 +02:00
|
|
|
def aroundReceive(receive: Receive, message: Any) = message match {
|
2013-11-20 13:47:42 +01:00
|
|
|
case PersistentBatch(b) ⇒
|
2013-11-12 09:02:02 +01:00
|
|
|
b.foreach(p ⇒ deleteMessage(p.sequenceNr, true))
|
2013-10-27 08:01:14 +01:00
|
|
|
throw new UnsupportedOperationException("Persistent command batches not supported")
|
2013-11-20 13:47:42 +01:00
|
|
|
case p: PersistentRepr ⇒
|
2013-11-12 09:02:02 +01:00
|
|
|
deleteMessage(p.sequenceNr, true)
|
2013-10-27 08:01:14 +01:00
|
|
|
throw new UnsupportedOperationException("Persistent commands not supported")
|
2014-01-17 06:58:25 +01:00
|
|
|
case WriteMessageSuccess(p) ⇒
|
2013-10-15 09:01:07 +02:00
|
|
|
withCurrentPersistent(p)(p ⇒ persistInvocations.head._2(p.payload))
|
|
|
|
|
onWriteComplete()
|
2014-01-17 06:58:25 +01:00
|
|
|
case e @ WriteMessageFailure(p, _) ⇒
|
2013-10-15 09:01:07 +02:00
|
|
|
Eventsourced.super.aroundReceive(receive, message) // stops actor by default
|
|
|
|
|
onWriteComplete()
|
2014-01-17 06:58:25 +01:00
|
|
|
case s @ WriteMessagesSuccess ⇒ Eventsourced.super.aroundReceive(receive, s)
|
|
|
|
|
case f: WriteMessagesFailure ⇒ Eventsourced.super.aroundReceive(receive, f)
|
|
|
|
|
case other ⇒ processorStash.stash()
|
2013-10-15 09:01:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def onWriteComplete(): Unit = {
|
|
|
|
|
persistInvocations = persistInvocations.tail
|
|
|
|
|
if (persistInvocations.isEmpty) {
|
|
|
|
|
currentState = processingCommands
|
2013-10-27 08:01:14 +01:00
|
|
|
processorStash.unstash()
|
2013-10-15 09:01:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private var persistInvocations: List[(Any, Any ⇒ Unit)] = Nil
|
2013-11-07 10:45:02 +01:00
|
|
|
private var persistentEventBatch: List[PersistentRepr] = Nil
|
2013-10-15 09:01:07 +02:00
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
private var currentState: State = recovering
|
2013-11-07 10:45:02 +01:00
|
|
|
private val processorStash = createStash()
|
2013-10-15 09:01:07 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Asynchronously persists `event`. On successful persistence, `handler` is called with the
|
|
|
|
|
* persisted event. It is guaranteed that no new commands will be received by a processor
|
|
|
|
|
* between a call to `persist` and the execution of its `handler`. This also holds for
|
|
|
|
|
* multiple `persist` calls per received command. Internally, this is achieved by stashing new
|
|
|
|
|
* commands and unstashing them when the `event` has been persisted and handled. The stash used
|
|
|
|
|
* for that is an internal stash which doesn't interfere with the user stash inherited from
|
|
|
|
|
* [[Processor]].
|
|
|
|
|
*
|
|
|
|
|
* An event `handler` may close over processor state and modify it. The `sender` of a persisted
|
|
|
|
|
* event is the sender of the corresponding command. This means that one can reply to a command
|
|
|
|
|
* sender within an event `handler`.
|
|
|
|
|
*
|
|
|
|
|
* Within an event handler, applications usually update processor state using persisted event
|
|
|
|
|
* data, notify listeners and reply to command senders.
|
|
|
|
|
*
|
|
|
|
|
* If persistence of an event fails, the processor will be stopped. This can be customized by
|
|
|
|
|
* handling [[PersistenceFailure]] in [[receiveCommand]].
|
|
|
|
|
*
|
|
|
|
|
* @param event event to be persisted.
|
|
|
|
|
* @param handler handler for each persisted `event`
|
|
|
|
|
*/
|
|
|
|
|
final def persist[A](event: A)(handler: A ⇒ Unit): Unit = {
|
|
|
|
|
persistInvocations = (event, handler.asInstanceOf[Any ⇒ Unit]) :: persistInvocations
|
2013-11-07 10:45:02 +01:00
|
|
|
persistentEventBatch = PersistentRepr(event) :: persistentEventBatch
|
2013-10-15 09:01:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Asynchronously persists `events` in specified order. This is equivalent to calling
|
2013-11-07 10:45:02 +01:00
|
|
|
* `persist[A](event: A)(handler: A => Unit)` multiple times with the same `handler`,
|
|
|
|
|
* except that `events` are persisted atomically with this method.
|
2013-10-15 09:01:07 +02:00
|
|
|
*
|
|
|
|
|
* @param events events to be persisted.
|
|
|
|
|
* @param handler handler for each persisted `events`
|
|
|
|
|
*/
|
|
|
|
|
final def persist[A](events: immutable.Seq[A])(handler: A ⇒ Unit): Unit =
|
|
|
|
|
events.foreach(persist(_)(handler))
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Replay handler that receives persisted events during recovery. If a state snapshot
|
|
|
|
|
* has been captured and saved, this handler will receive a [[SnapshotOffer]] message
|
|
|
|
|
* followed by events that are younger than the offered snapshot.
|
|
|
|
|
*
|
|
|
|
|
* This handler must not have side-effects other than changing processor state i.e. it
|
|
|
|
|
* should not perform actions that may fail, such as interacting with external services,
|
|
|
|
|
* for example.
|
|
|
|
|
*
|
|
|
|
|
* @see [[Recover]]
|
|
|
|
|
*/
|
|
|
|
|
def receiveReplay: Receive
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Command handler. Typically validates commands against current state (and/or by
|
|
|
|
|
* communication with other actors). On successful validation, one or more events are
|
|
|
|
|
* derived from a command and these events are then persisted by calling `persist`.
|
|
|
|
|
* Commands sent to event sourced processors should not be [[Persistent]] messages.
|
|
|
|
|
*/
|
|
|
|
|
def receiveCommand: Receive
|
|
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
override def unstashAll() {
|
|
|
|
|
// Internally, all messages are processed by unstashing them from
|
|
|
|
|
// the internal stash one-by-one. Hence, an unstashAll() from the
|
|
|
|
|
// user stash must be prepended to the internal stash.
|
|
|
|
|
processorStash.prepend(clearStash())
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-15 09:01:07 +02:00
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*/
|
|
|
|
|
final override protected[akka] def aroundReceive(receive: Receive, message: Any) {
|
|
|
|
|
currentState.aroundReceive(receive, message)
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
/**
|
|
|
|
|
* Calls `super.preRestart` then unstashes all messages from the internal stash.
|
|
|
|
|
*/
|
|
|
|
|
override def preRestart(reason: Throwable, message: Option[Any]) {
|
|
|
|
|
processorStash.unstashAll()
|
2013-11-20 13:47:42 +01:00
|
|
|
super.preRestart(reason, message)
|
2013-10-27 08:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calls `super.postStop` then unstashes all messages from the internal stash.
|
|
|
|
|
*/
|
|
|
|
|
override def postStop() {
|
|
|
|
|
processorStash.unstashAll()
|
2013-11-20 13:47:42 +01:00
|
|
|
super.postStop()
|
2013-10-27 08:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
2013-10-15 09:01:07 +02:00
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*/
|
|
|
|
|
protected[persistence] val initialBehavior: Receive = {
|
|
|
|
|
case Persistent(payload, _) if receiveReplay.isDefinedAt(payload) && recoveryRunning ⇒
|
|
|
|
|
receiveReplay(payload)
|
|
|
|
|
case s: SnapshotOffer if receiveReplay.isDefinedAt(s) ⇒
|
|
|
|
|
receiveReplay(s)
|
|
|
|
|
case f: RecoveryFailure if receiveReplay.isDefinedAt(f) ⇒
|
|
|
|
|
receiveReplay(f)
|
|
|
|
|
case msg if receiveCommand.isDefinedAt(msg) ⇒
|
|
|
|
|
receiveCommand(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An event sourced processor.
|
|
|
|
|
*/
|
|
|
|
|
trait EventsourcedProcessor extends Processor with Eventsourced {
|
|
|
|
|
final def receive = initialBehavior
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Java API: an event sourced processor.
|
2013-10-15 09:01:07 +02:00
|
|
|
*/
|
|
|
|
|
abstract class UntypedEventsourcedProcessor extends UntypedProcessor with Eventsourced {
|
|
|
|
|
final def onReceive(message: Any) = initialBehavior(message)
|
|
|
|
|
|
|
|
|
|
final def receiveReplay: Receive = {
|
|
|
|
|
case msg ⇒ onReceiveReplay(msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final def receiveCommand: Receive = {
|
|
|
|
|
case msg ⇒ onReceiveCommand(msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Java API: asynchronously persists `event`. On successful persistence, `handler` is called with the
|
2013-10-15 09:01:07 +02:00
|
|
|
* persisted event. It is guaranteed that no new commands will be received by a processor
|
|
|
|
|
* between a call to `persist` and the execution of its `handler`. This also holds for
|
|
|
|
|
* multiple `persist` calls per received command. Internally, this is achieved by stashing new
|
|
|
|
|
* commands and unstashing them when the `event` has been persisted and handled. The stash used
|
|
|
|
|
* for that is an internal stash which doesn't interfere with the user stash inherited from
|
|
|
|
|
* [[UntypedProcessor]].
|
|
|
|
|
*
|
|
|
|
|
* An event `handler` may close over processor state and modify it. The `getSender()` of a persisted
|
|
|
|
|
* event is the sender of the corresponding command. This means that one can reply to a command
|
|
|
|
|
* sender within an event `handler`.
|
|
|
|
|
*
|
|
|
|
|
* Within an event handler, applications usually update processor state using persisted event
|
|
|
|
|
* data, notify listeners and reply to command senders.
|
|
|
|
|
*
|
|
|
|
|
* If persistence of an event fails, the processor will be stopped. This can be customized by
|
|
|
|
|
* handling [[PersistenceFailure]] in [[onReceiveCommand]].
|
|
|
|
|
*
|
|
|
|
|
* @param event event to be persisted.
|
|
|
|
|
* @param handler handler for each persisted `event`
|
|
|
|
|
*/
|
|
|
|
|
final def persist[A](event: A, handler: Procedure[A]): Unit =
|
|
|
|
|
persist(event)(event ⇒ handler(event))
|
|
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Java API: asynchronously persists `events` in specified order. This is equivalent to calling
|
|
|
|
|
* `persist[A](event: A, handler: Procedure[A])` multiple times with the same `handler`,
|
|
|
|
|
* except that `events` are persisted atomically with this method.
|
2013-10-15 09:01:07 +02:00
|
|
|
*
|
|
|
|
|
* @param events events to be persisted.
|
|
|
|
|
* @param handler handler for each persisted `events`
|
|
|
|
|
*/
|
|
|
|
|
final def persist[A](events: JIterable[A], handler: Procedure[A]): Unit =
|
|
|
|
|
persist(Util.immutableSeq(events))(event ⇒ handler(event))
|
|
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Java API: replay handler that receives persisted events during recovery. If a state snapshot
|
2013-10-15 09:01:07 +02:00
|
|
|
* has been captured and saved, this handler will receive a [[SnapshotOffer]] message
|
|
|
|
|
* followed by events that are younger than the offered snapshot.
|
|
|
|
|
*
|
|
|
|
|
* This handler must not have side-effects other than changing processor state i.e. it
|
|
|
|
|
* should not perform actions that may fail, such as interacting with external services,
|
|
|
|
|
* for example.
|
|
|
|
|
*
|
|
|
|
|
* @see [[Recover]]
|
|
|
|
|
*/
|
|
|
|
|
def onReceiveReplay(msg: Any): Unit
|
|
|
|
|
|
|
|
|
|
/**
|
2013-11-07 10:45:02 +01:00
|
|
|
* Java API: command handler. Typically validates commands against current state (and/or by
|
2013-10-15 09:01:07 +02:00
|
|
|
* communication with other actors). On successful validation, one or more events are
|
|
|
|
|
* derived from a command and these events are then persisted by calling `persist`.
|
2013-10-27 08:01:14 +01:00
|
|
|
* Commands sent to event sourced processors must not be [[Persistent]] or
|
|
|
|
|
* [[PersistentBatch]] messages. In this case an `UnsupportedOperationException` is
|
|
|
|
|
* thrown by the processor.
|
2013-10-15 09:01:07 +02:00
|
|
|
*/
|
|
|
|
|
def onReceiveCommand(msg: Any): Unit
|
2013-11-07 10:45:02 +01:00
|
|
|
}
|