!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:
Konrad 'ktoso' Malawski 2014-05-21 01:35:21 +02:00
parent 5f3d6029b1
commit d51b79c95a
32 changed files with 907 additions and 134 deletions

View file

@ -4,13 +4,17 @@
package docs.persistence;
import java.util.concurrent.TimeUnit;
import scala.Option;
import scala.concurrent.duration.Duration;
import akka.actor.*;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.japi.Procedure;
import akka.persistence.*;
import scala.Option;
import scala.concurrent.duration.Duration;
import java.util.concurrent.TimeUnit;
import static java.util.Arrays.asList;
public class PersistenceDocTest {
@ -353,11 +357,11 @@ public class PersistenceDocTest {
static Object o8 = new Object() {
//#reliable-event-delivery
class MyEventsourcedProcessor extends UntypedEventsourcedProcessor {
class MyPersistentActor extends UntypedPersistentActor {
private ActorRef destination;
private ActorRef channel;
public MyEventsourcedProcessor(ActorRef destination) {
public MyPersistentActor(ActorRef destination) {
this.destination = destination;
this.channel = getContext().actorOf(Channel.props(), "channel");
}
@ -390,6 +394,53 @@ public class PersistenceDocTest {
};
static Object o9 = new Object() {
//#persist-async
class MyPersistentActor extends UntypedPersistentActor {
@Override
public void onReceiveRecover(Object msg) {
// handle recovery here
}
@Override
public void onReceiveCommand(Object msg) {
sender().tell(msg, getSelf());
persistAsync(String.format("evt-%s-1", msg), new Procedure<String>(){
@Override
public void apply(String event) throws Exception {
sender().tell(event, self());
}
});
persistAsync(String.format("evt-%s-2", msg), new Procedure<String>(){
@Override
public void apply(String event) throws Exception {
sender().tell(event, self());
}
});
}
}
//#persist-async
public void usage() {
final ActorSystem system = ActorSystem.create("example");
//#view-update
final ActorRef processor = system.actorOf(Props.create(MyPersistentActor.class));
processor.tell("a", null);
processor.tell("b", null);
// possible order of received messages:
// a
// b
// evt-a-1
// evt-a-2
// evt-b-1
// evt-b-2
//#view-update
}
};
static Object o10 = new Object() {
//#view
class MyView extends UntypedView {
@Override

View file

@ -442,13 +442,13 @@ 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 ``AbstractEventsourcedProcessor`` abstract class (which implements
Akka persistence supports event sourcing with the ``AbstractPersistentActor`` abstract class (which implements
event sourcing as a pattern on top of command sourcing). A processor that extends this abstract class does not handle
``Persistent`` messages directly but uses the ``persist`` method to persist and handle events. The behavior of an
``AbstractEventsourcedProcessor`` is defined by implementing ``receiveRecover`` and ``receiveCommand``. This is
``AbstractEventsPersistentActordefined by implementing ``receiveRecover`` and ``receiveCommand``. This is
demonstrated in the following example.
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/sample/persistence/EventsourcedExample.java#eventsourced-example
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/sample/persistence/PersistentActorExample.java#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``.
@ -473,7 +473,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 in Java with Lambdas <http://www.typesafe.com/activator/template/akka-sample-persistence-java-lambda>`_.
It contains instructions on how to run the ``EventsourcedExample``.
It contains instructions on how to run the ``PersistentActorExample``.
.. note::
@ -518,9 +518,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 ``AbstractEventsourcedProcessor`` to ensure atomic
``PersistentBatch`` messages, for example, are used internally by an ``AbstractEventsourcedPersistentActor 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 ``AbstractEventsourcedProcessor``
journal (even if ``persist`` is called multiple times per command). The recovery of an ``AbstractPersistentActor``
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-java-lambda` are also batched. The maximum

View file

@ -48,9 +48,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 ``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.
* *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
@ -79,6 +84,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 abstract ``UntypedProcessor`` class and implementing the
``onReceive`` method.
@ -451,6 +462,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
@ -468,13 +484,13 @@ 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 abstract ``UntypedEventsourcedProcessor`` class (which implements
Akka persistence supports event sourcing with the abstract ``UntypedPersistentActor`` class (which implements
event sourcing as a pattern on top of command sourcing). A processor that extends this abstract class does not handle
``Persistent`` messages directly but uses the ``persist`` method to persist and handle events. The behavior of an
``UntypedEventsourcedProcessor`` is defined by implementing ``onReceiveRecover`` and ``onReceiveCommand``. This is
``UntypedPersistentActor`` is defined by implementing ``onReceiveRecover`` and ``onReceiveCommand``. This is
demonstrated in the following example.
.. includecode:: ../../../akka-samples/akka-sample-persistence-java/src/main/java/sample/persistence/EventsourcedExample.java#eventsourced-example
.. includecode:: ../../../akka-samples/akka-sample-persistence-java/src/main/java/sample/persistence/PersistentActorExample.java#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``.
@ -499,7 +515,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 Java <http://www.typesafe.com/activator/template/akka-sample-persistence-java>`_.
It contains instructions on how to run the ``EventsourcedExample``.
It contains instructions on how to run the ``PersistentActorExample``.
.. note::
@ -508,6 +524,29 @@ 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-java:
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/PersistenceDocTest.java#persist-async
.. note::
In order to implement the pattern known as "*command sourcing*" simply ``persistAsync`` all incoming events right away,
and handle them in the callback.
Reliable event delivery
-----------------------
@ -543,9 +582,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 ``UntypedEventsourcedProcessor`` to ensure atomic
``PersistentBatch`` messages, for example, are used internally by an ``UntypedPersistentActor`` 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 ``UntypedEventsourcedProcessor``
journal (even if ``persist`` is called multiple times per command). The recovery of an ``UntypedPersistentActor``
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-java` are also batched. The maximum confirmation

View file

@ -1,8 +1,8 @@
.. _migration-eventsourced-2.3:
#######################################################
Migration Guide Eventsourced to Akka Persistence 2.3.x
#######################################################
######################################################
Migration Guide Eventsourced to Akka Persistence 2.3.x
######################################################
General notes
=============

View file

@ -0,0 +1,67 @@
.. _migration-guide-persistence-experimental-2.3.x-2.4.x:
#####################################################
Migration Guide Akka Persistence (experimental) 2.3.3
#####################################################
**Akka Persistence** is an **experimental module**, which means that neither Binary Compatibility nor API stability
is provided for Persistence while under the *experimental* flag. The goal of this phase is to gather user feedback
before we freeze the APIs in a major release.
Renamed EventsourcedProcessor to PersistentActor
================================================
``EventsourcedProcessor`` is now deprecated and replaced by ``PersistentActor`` which provides the same (and more) API.
Migrating to ``2.4.x`` is as simple as changing all your classes to extending ``PersistentActor``.
Replace all classes like::
class DeprecatedProcessor extends EventsourcedProcessor { /*...*/ }
To extend ``PersistentActor``::
class NewPersistentProcessor extends PersistentActor { /*...*/ }
No other API changes are required for this migration.
Removed Processor in favour of extending PersistentActor with persistAsync
==========================================================================
The ``Processor`` is now deprecated since ``2.3.4`` and will be removed in ``2.4.x``.
It's semantics replicated in ``PersistentActor`` in the form of an additional ``persist`` method: ``persistAsync``.
In essence, the difference betwen ``persist`` and ``persistAsync`` is that the former will stash all incomming commands
until all persist callbacks have been processed, whereas the latter does not stash any commands. The new ``persistAsync``
should be used in cases of low consistency yet high responsiveness requirements, the Actor can keep processing incomming
commands, even though not all previous events have been handled.
When these ``persist`` and ``persistAsync`` are used together in the same ``PersistentActor``, the ``persist``
logic will win over the async version so that all guarantees concerning persist still hold. This will however lower
the throughput
Now deprecated code using Processor::
class OldProcessor extends Processor {
def receive = {
case Persistent(cmd) => sender() ! cmd
}
}
Replacement code, with the same semantics, using PersistentActor::
class NewProcessor extends PersistentActor {
def receiveCommand = {
case cmd =>
persistAsync(cmd) { e => sender() ! e }
}
def receiveEvent = {
case _ => // logic for handling replay
}
}
It is worth pointing out that using ``sender()`` inside the persistAsync callback block is **valid**, and does *not* suffer
any of the problems Futures have when closing over the sender reference.
Using the``PersistentActor`` instead of ``Processor`` also shifts the responsibility of deciding if a message should be persisted
to the receiver instead of the sender of the message. Previously, using ``Processor``, clients would have to wrap messages as ``Persistent(cmd)``
manually, as well as have to be aware of the receiver being a ``Processor``, which didn't play well with transparency of the ActorRefs in general.

View file

@ -11,4 +11,5 @@ Migration Guides
migration-guide-2.1.x-2.2.x
migration-guide-2.2.x-2.3.x
migration-guide-2.3.x-2.4.x
migration-guide-persistence-experimental-2.3.x-2.4.x
migration-guide-eventsourced-2.3.x

View file

@ -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

View file

@ -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