!per persistAsync
Breaks binary compatibility because adding new methods to Eventsourced trait. Since akka-persistence is experimental this is ok, yet source-level compatibility has been perserved thankfuly :-) Deprecates: * Rename of EventsourcedProcessor -> PersistentActor * Processor -> suggest using PersistentActor * Migration guide for akka-persistence is separate, as wel'll deprecate in minor versions (its experimental) * Persistent as well as ConfirmablePersistent - since Processor, their main user will be removed soon. Other changes: * persistAsync works as expected when mixed with persist * A counter must be kept for pending stashing invocations * Uses only 1 shared list buffer for persit / persistAsync * Includes small benchmark * Docs also include info about not using Persistent() wrapper * uses java LinkedList, for best performance of append / head on persistInvocations; the get(0) is safe, because these msgs only come in response to persistInvocations * Renamed internal *MessagesSuccess/Failure messages because we kept small mistakes seeing the class "with s" and "without s" as the same * Updated everything that refered to EventsourcedProcessor to PersistentActor, including samples Refs #15227 Conflicts: akka-docs/rst/project/migration-guides.rst akka-persistence/src/main/scala/akka/persistence/JournalProtocol.scala akka-persistence/src/main/scala/akka/persistence/Persistent.scala akka-persistence/src/test/scala/akka/persistence/PersistentActorSpec.scala project/AkkaBuild.scala
This commit is contained in:
parent
5f3d6029b1
commit
d51b79c95a
32 changed files with 907 additions and 134 deletions
|
|
@ -7,7 +7,7 @@ package docs.persistence
|
|||
import scala.concurrent.duration._
|
||||
import scala.language.postfixOps
|
||||
|
||||
import akka.actor.{ Actor, ActorSystem }
|
||||
import akka.actor.{ Props, Actor, ActorSystem }
|
||||
import akka.persistence._
|
||||
|
||||
trait PersistenceDocSpec {
|
||||
|
|
@ -314,7 +314,7 @@ trait PersistenceDocSpec {
|
|||
import akka.actor.ActorRef
|
||||
|
||||
//#reliable-event-delivery
|
||||
class MyEventsourcedProcessor(destination: ActorRef) extends EventsourcedProcessor {
|
||||
class MyPersistentActor(destination: ActorRef) extends PersistentActor {
|
||||
val channel = context.actorOf(Channel.props("channel"))
|
||||
|
||||
def handleEvent(event: String) = {
|
||||
|
|
@ -337,6 +337,42 @@ trait PersistenceDocSpec {
|
|||
}
|
||||
//#reliable-event-delivery
|
||||
}
|
||||
|
||||
new AnyRef {
|
||||
import akka.actor.ActorRef
|
||||
|
||||
val processor = system.actorOf(Props[MyPersistentActor]())
|
||||
|
||||
//#persist-async
|
||||
class MyPersistentActor extends PersistentActor {
|
||||
|
||||
def receiveRecover: Receive = {
|
||||
case _ => // handle recovery here
|
||||
}
|
||||
|
||||
def receiveCommand: Receive = {
|
||||
case c: String => {
|
||||
sender() ! c
|
||||
persistAsync(s"evt-$c-1") { e => sender() ! e }
|
||||
persistAsync(s"evt-$c-2") { e => sender() ! e }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// usage
|
||||
processor ! "a"
|
||||
processor ! "b"
|
||||
|
||||
// possible order of received messages:
|
||||
// a
|
||||
// b
|
||||
// evt-a-1
|
||||
// evt-a-2
|
||||
// evt-b-1
|
||||
// evt-b-2
|
||||
|
||||
//#persist-async
|
||||
}
|
||||
new AnyRef {
|
||||
import akka.actor.Props
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,14 @@ Akka persistence is a separate jar file. Make sure that you have the following d
|
|||
Architecture
|
||||
============
|
||||
|
||||
* *Processor*: A processor is a persistent, stateful actor. Messages sent to a processor are written to a journal
|
||||
before its ``receive`` method is called. When a processor is started or restarted, journaled messages are replayed
|
||||
to that processor, so that it can recover internal state from these messages.
|
||||
* *Processor* (deprecated, use *PersistentActor* instead): A processor is a persistent, stateful actor. Messages sent
|
||||
to a processor are written to a journal before its ``onReceive`` method is called. When a processor is started or
|
||||
restarted, journaled messages are replayed to that processor, so that it can recover internal state from these messages.
|
||||
|
||||
* *PersistentActor*: Is a persistent, stateful actor. It is able to persist events to a journal and can react to
|
||||
them in a thread-safe manner. It can be used to implement both *command* as well as *event sourced* actors.
|
||||
When a persistent actor is started or restarted, journaled messages are replayed to that actor, so that it can
|
||||
recover internal state from these messages.
|
||||
|
||||
* *View*: A view is a persistent, stateful actor that receives journaled messages that have been written by another
|
||||
processor. A view itself does not journal new messages, instead, it updates internal state only from a processor's
|
||||
|
|
@ -67,6 +72,12 @@ Architecture
|
|||
Processors
|
||||
==========
|
||||
|
||||
.. warning::
|
||||
``Processor`` is deprecated. Instead the current ``PersistentActor`` will be extended to provide equivalent
|
||||
functionality if required (by introducing the ``persistAsync`` method).
|
||||
For details see `Relaxed local consistency requirements and high throughput use-cases`_ as well as the discussion
|
||||
and pull requests related to this `issue on Github <https://github.com/akka/akka/issues/15230>`_.
|
||||
|
||||
A processor can be implemented by extending the ``Processor`` trait and implementing the ``receive`` method.
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#definition
|
||||
|
|
@ -463,6 +474,11 @@ use the ``deleteSnapshots`` method.
|
|||
Event sourcing
|
||||
==============
|
||||
|
||||
.. note::
|
||||
The ``PersistentActor`` introduced in this section was previously known as ``EventsourcedProcessor``
|
||||
which was a subset of the ``PersistentActor``. Migrating your code to use persistent actors instead is
|
||||
very simple and is explained in the :ref:`migration-guide-persistence-experimental-2.3.x-2.4.x`.
|
||||
|
||||
In all the examples so far, messages that change a processor's state have been sent as ``Persistent`` messages
|
||||
by an application, so that they can be replayed during recovery. From this point of view, the journal acts as
|
||||
a write-ahead-log for whatever ``Persistent`` messages a processor receives. This is also known as *command
|
||||
|
|
@ -480,12 +496,12 @@ also process commands that do not change application state, such as query comman
|
|||
|
||||
.. _Event Sourcing: http://martinfowler.com/eaaDev/EventSourcing.html
|
||||
|
||||
Akka persistence supports event sourcing with the ``EventsourcedProcessor`` trait (which implements event sourcing
|
||||
Akka persistence supports event sourcing with the ``PersistentActor`` trait (which implements event sourcing
|
||||
as a pattern on top of command sourcing). A processor that extends this trait does not handle ``Persistent`` messages
|
||||
directly but uses the ``persist`` method to persist and handle events. The behavior of an ``EventsourcedProcessor``
|
||||
directly but uses the ``persist`` method to persist and handle events. The behavior of an ``PersistentActor``
|
||||
is defined by implementing ``receiveRecover`` and ``receiveCommand``. This is demonstrated in the following example.
|
||||
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-scala/src/main/scala/sample/persistence/EventsourcedExample.scala#eventsourced-example
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-scala/src/main/scala/sample/persistence/PersistentActorExample.scala#persistent-actor-example
|
||||
|
||||
The example defines two data types, ``Cmd`` and ``Evt`` to represent commands and events, respectively. The
|
||||
``state`` of the ``ExampleProcessor`` is a list of persisted event data contained in ``ExampleState``.
|
||||
|
|
@ -510,7 +526,7 @@ calls in context of a single command.
|
|||
|
||||
The easiest way to run this example yourself is to download `Typesafe Activator <http://www.typesafe.com/platform/getstarted>`_
|
||||
and open the tutorial named `Akka Persistence Samples with Scala <http://www.typesafe.com/activator/template/akka-sample-persistence-scala>`_.
|
||||
It contains instructions on how to run the ``EventsourcedExample``.
|
||||
It contains instructions on how to run the ``PersistentActorExample``.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -519,6 +535,34 @@ It contains instructions on how to run the ``EventsourcedExample``.
|
|||
recovery you need to take special care to perform the same state transitions with ``become`` and
|
||||
``unbecome`` in the ``receiveRecover`` method as you would have done in the command handler.
|
||||
|
||||
.. _persist-async-scala:
|
||||
|
||||
Relaxed local consistency requirements and high throughput use-cases
|
||||
--------------------------------------------------------------------
|
||||
|
||||
If faced with Relaxed local consistency requirements and high throughput demands sometimes ``PersistentActor`` and it's
|
||||
``persist`` may not be enough in terms of consuming incoming Commands at a high rate, because it has to wait until all
|
||||
Events related to a given Command are processed in order to start processing the next Command. While this abstraction is
|
||||
very useful for most cases, sometimes you may be faced with relaxed requirements about consistency – for example you may
|
||||
want to process commands as fast as you can, assuming that Event will eventually be persisted and handled properly in
|
||||
the background and retroactively reacting to persistence failures if needed.
|
||||
|
||||
The ``persistAsync`` method provides a tool for implementing high-throughput processors. It will *not*
|
||||
stash incoming Commands while the Journal is still working on persisting and/or user code is executing event callbacks.
|
||||
|
||||
In the below example, the event callbacks may be called "at any time", even after the next Command has been processed.
|
||||
The ordering between events is still guaranteed ("evt-b-1" will be sent after "evt-a-2", which will be sent after "evt-a-1" etc.).
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#persist-async
|
||||
|
||||
Notice that the client does not have to wrap any messages in the `Persistent` class in order to obtain "command sourcing like"
|
||||
semantics. It's up to the processor to decide about persisting (or not) of messages, unlike ``Processor`` where this decision
|
||||
was made by the sender.
|
||||
|
||||
|
||||
.. note::
|
||||
In order to implement the "*command sourcing*" simply call ``persistAsync(cmd)(...)`` right away on all incomming
|
||||
messages right away, and handle them in the callback.
|
||||
|
||||
Reliable event delivery
|
||||
-----------------------
|
||||
|
|
@ -556,9 +600,9 @@ Applications that want to have more explicit control over batch writes and batch
|
|||
size is greater than ``max-message-batch-size``. Also, a ``PersistentBatch`` is written isolated from other batches.
|
||||
``Persistent`` messages contained in a ``PersistentBatch`` are received individually by a processor.
|
||||
|
||||
``PersistentBatch`` messages, for example, are used internally by an ``EventsourcedProcessor`` to ensure atomic
|
||||
``PersistentBatch`` messages, for example, are used internally by an ``PersistentActor`` to ensure atomic
|
||||
writes of events. All events that are persisted in context of a single command are written as a single batch to the
|
||||
journal (even if ``persist`` is called multiple times per command). The recovery of an ``EventsourcedProcessor``
|
||||
journal (even if ``persist`` is called multiple times per command). The recovery of an ``PersistentActor``
|
||||
will therefore never be done partially (with only a subset of events persisted by a single command).
|
||||
|
||||
Confirmation and deletion operations performed by :ref:`channels` are also batched. The maximum confirmation
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue