2013-12-14 17:27:36 +01:00
|
|
|
|
.. _persistence-scala:
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
###########
|
|
|
|
|
|
Persistence
|
|
|
|
|
|
###########
|
|
|
|
|
|
|
2013-10-09 13:11:53 +02:00
|
|
|
|
Akka persistence enables stateful actors to persist their internal state so that it can be recovered when an actor
|
2014-01-17 06:58:25 +01:00
|
|
|
|
is started, restarted after a JVM crash or by a supervisor, or migrated in a cluster. The key concept behind Akka
|
|
|
|
|
|
persistence is that only changes to an actor's internal state are persisted but never its current state directly
|
|
|
|
|
|
(except for optional snapshots). These changes are only ever appended to storage, nothing is ever mutated, which
|
|
|
|
|
|
allows for very high transaction rates and efficient replication. Stateful actors are recovered by replaying stored
|
|
|
|
|
|
changes to these actors from which they can rebuild internal state. This can be either the full history of changes
|
|
|
|
|
|
or starting from a snapshot which can dramatically reduce recovery times. Akka persistence also provides point-to-point
|
2014-06-25 12:51:21 +02:00
|
|
|
|
communication with at-least-once message delivery semantics.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
|
|
|
|
This module is marked as **“experimental”** as of its introduction in Akka 2.3.0. We will continue to
|
|
|
|
|
|
improve this API based on our users’ feedback, which implies that while we try to keep incompatible
|
|
|
|
|
|
changes to a minimum the binary compatibility guarantee for maintenance releases does not apply to the
|
|
|
|
|
|
contents of the ``akka.persistence`` package.
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
Akka persistence is inspired by and the official replacement of the `eventsourced`_ library. It follows the same
|
2014-02-24 10:34:22 +01:00
|
|
|
|
concepts and architecture of `eventsourced`_ but significantly differs on API and implementation level. See also
|
|
|
|
|
|
:ref:`migration-eventsourced-2.3`
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
|
.. _eventsourced: https://github.com/eligosource/eventsourced
|
|
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
Changes in Akka 2.3.4
|
|
|
|
|
|
=====================
|
|
|
|
|
|
|
|
|
|
|
|
In Akka 2.3.4 several of the concepts of the earlier versions were collapsed and simplified.
|
|
|
|
|
|
In essence; ``Processor`` and ``EventsourcedProcessor`` are replaced by ``PersistentActor``. ``Channel``
|
|
|
|
|
|
and ``PersistentChannel`` are replaced by ``AtLeastOnceDelivery``. ``View`` is replaced by ``PersistentView``.
|
|
|
|
|
|
|
|
|
|
|
|
See full details of the changes in the :ref:`migration-guide-persistence-experimental-2.3.x-2.4.x`.
|
|
|
|
|
|
The old classes are still included, and deprecated, for a while to make the transition smooth.
|
|
|
|
|
|
In case you need the old documentation it is located `here <http://doc.akka.io/docs/akka/2.3.3/scala/persistence.html>`_.
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
|
Dependencies
|
|
|
|
|
|
============
|
|
|
|
|
|
|
|
|
|
|
|
Akka persistence is a separate jar file. Make sure that you have the following dependency in your project::
|
|
|
|
|
|
|
2013-09-18 11:55:29 +02:00
|
|
|
|
"com.typesafe.akka" %% "akka-persistence-experimental" % "@version@" @crossString@
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
Architecture
|
|
|
|
|
|
============
|
|
|
|
|
|
|
2014-05-21 01:35:21 +02:00
|
|
|
|
* *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.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
* *PersistentView*: A view is a persistent, stateful actor that receives journaled messages that have been written by another
|
2014-06-25 12:51:21 +02:00
|
|
|
|
persistent actor. A view itself does not journal new messages, instead, it updates internal state only from a persistent actor's
|
2014-01-17 06:58:25 +01:00
|
|
|
|
replicated message stream.
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
* *Streams*: Messages written by a persistent actor can be published in compliance with the `Reactive Streams`_ specification.
|
|
|
|
|
|
Only those messages that are explicitly requested from downstream persistent actors are actually pulled from a persistent actor's
|
2014-05-01 09:05:15 +02:00
|
|
|
|
journal.
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
* *AtLeastOnceDelivery*: To send messages with at-least-once delivery semantics to destinations, also in
|
2014-01-17 06:58:25 +01:00
|
|
|
|
case of sender and receiver JVM crashes.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
* *Journal*: A journal stores the sequence of messages sent to a persistent actor. An application can control which messages
|
|
|
|
|
|
are journaled and which are received by the persistent actor without being journaled. The storage backend of a journal is
|
2014-01-17 06:58:25 +01:00
|
|
|
|
pluggable. The default journal storage plugin writes to the local filesystem, replicated journals are available as
|
2014-01-25 08:35:06 +01:00
|
|
|
|
`Community plugins`_.
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
* *Snapshot store*: A snapshot store persists snapshots of a persistent actor's or a view's internal state. Snapshots are
|
2014-01-17 06:58:25 +01:00
|
|
|
|
used for optimizing recovery times. The storage backend of a snapshot store is pluggable. The default snapshot
|
|
|
|
|
|
storage plugin writes to the local filesystem.
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
2014-02-20 11:47:43 +01:00
|
|
|
|
.. _Community plugins: http://akka.io/community/
|
2014-05-01 09:05:15 +02:00
|
|
|
|
.. _Reactive Streams: http://www.reactive-streams.org/
|
2014-01-25 08:35:06 +01:00
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
.. _event-sourcing:
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Event sourcing
|
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
|
|
The basic idea behind `Event Sourcing`_ is quite simple. A persistent actor receives a (non-persistent) command
|
|
|
|
|
|
which is first validated if it can be applied to the current state. Here, validation can mean anything, from simple
|
|
|
|
|
|
inspection of a command message's fields up to a conversation with several external services, for example.
|
|
|
|
|
|
If validation succeeds, events are generated from the command, representing the effect of the command. These events
|
|
|
|
|
|
are then persisted and, after successful persistence, used to change the actor's state. When the persistent actor
|
|
|
|
|
|
needs to be recovered, only the persisted events are replayed of which we know that they can be successfully applied.
|
|
|
|
|
|
In other words, events cannot fail when being replayed to a persistent actor, in contrast to commands. Event sourced
|
|
|
|
|
|
actors may of course also process commands that do not change application state, such as query commands, for example.
|
|
|
|
|
|
|
|
|
|
|
|
.. _Event Sourcing: http://martinfowler.com/eaaDev/EventSourcing.html
|
|
|
|
|
|
|
|
|
|
|
|
Akka persistence supports event sourcing with the ``PersistentActor`` trait. An actor that extends this trait uses the
|
|
|
|
|
|
``persist`` method to persist and handle events. The behavior of a ``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/PersistentActorExample.scala#persistent-actor-example
|
|
|
|
|
|
|
|
|
|
|
|
The example defines two data types, ``Cmd`` and ``Evt`` to represent commands and events, respectively. The
|
2014-06-26 13:56:01 +02:00
|
|
|
|
``state`` of the ``ExamplePersistentActor`` is a list of persisted event data contained in ``ExampleState``.
|
2014-06-25 12:51:21 +02:00
|
|
|
|
|
|
|
|
|
|
The persistent actor's ``receiveRecover`` method defines how ``state`` is updated during recovery by handling ``Evt``
|
|
|
|
|
|
and ``SnapshotOffer`` messages. The persistent actor's ``receiveCommand`` method is a command handler. In this example,
|
|
|
|
|
|
a command is handled by generating two events which are then persisted and handled. Events are persisted by calling
|
|
|
|
|
|
``persist`` with an event (or a sequence of events) as first argument and an event handler as second argument.
|
|
|
|
|
|
|
|
|
|
|
|
The ``persist`` method persists events asynchronously and the event handler is executed for successfully persisted
|
|
|
|
|
|
events. Successfully persisted events are internally sent back to the persistent actor as individual messages that trigger
|
|
|
|
|
|
event handler executions. An event handler may close over persistent actor state and mutate it. The sender of a persisted
|
|
|
|
|
|
event is the sender of the corresponding command. This allows event handlers to reply to the sender of a command
|
|
|
|
|
|
(not shown).
|
|
|
|
|
|
|
|
|
|
|
|
The main responsibility of an event handler is changing persistent actor state using event data and notifying others
|
|
|
|
|
|
about successful state changes by publishing events.
|
|
|
|
|
|
|
|
|
|
|
|
When persisting events with ``persist`` it is guaranteed that the persistent actor will not receive further commands between
|
|
|
|
|
|
the ``persist`` call and the execution(s) of the associated event handler. This also holds for multiple ``persist``
|
|
|
|
|
|
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 ``PersistentActorExample``.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
It's also possible to switch between different command handlers during normal processing and recovery
|
|
|
|
|
|
with ``context.become()`` and ``context.unbecome()``. To get the actor into the same state after
|
|
|
|
|
|
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.
|
2014-05-21 01:35:21 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Identifiers
|
|
|
|
|
|
-----------
|
|
|
|
|
|
|
2014-06-26 13:56:01 +02:00
|
|
|
|
A persistent actor must have an identifier that doesn't change across different actor incarnations.
|
|
|
|
|
|
The identifier must be defined with the ``persistenceId`` method.
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#persistence-id-override
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-02-24 10:34:22 +01:00
|
|
|
|
.. _recovery:
|
|
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
|
Recovery
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
By default, a persistent actor is automatically recovered on start and on restart by replaying journaled messages.
|
|
|
|
|
|
New messages sent to a persistent actor during recovery do not interfere with replayed messages. New messages will
|
|
|
|
|
|
only be received by a persistent actor after recovery completes.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
Recovery customization
|
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2013-09-15 09:04:05 +02:00
|
|
|
|
Automated recovery on start can be disabled by overriding ``preStart`` with an empty implementation.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recover-on-start-disabled
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
In this case, a persistent actor must be recovered explicitly by sending it a ``Recover()`` message.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recover-explicit
|
|
|
|
|
|
|
2013-09-15 09:04:05 +02:00
|
|
|
|
If not overridden, ``preStart`` sends a ``Recover()`` message to ``self``. Applications may also override
|
|
|
|
|
|
``preStart`` to define further ``Recover()`` parameters such as an upper sequence number bound, for example.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recover-on-start-custom
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Upper sequence number bounds can be used to recover a persistent actor to past state instead of current state. Automated
|
2013-11-07 10:45:02 +01:00
|
|
|
|
recovery on restart can be disabled by overriding ``preRestart`` with an empty implementation.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recover-on-restart-disabled
|
|
|
|
|
|
|
|
|
|
|
|
Recovery status
|
|
|
|
|
|
^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
A persistent actor can query its own recovery status via the methods
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recovery-status
|
|
|
|
|
|
|
2014-03-24 15:35:54 +01:00
|
|
|
|
Sometimes there is a need for performing additional initialization when the
|
2014-06-25 12:51:21 +02:00
|
|
|
|
recovery has completed, before processing any other message sent to the persistent actor.
|
|
|
|
|
|
The persistent actor will receive a special :class:`RecoveryCompleted` message right after recovery
|
|
|
|
|
|
and before any other received messages.
|
|
|
|
|
|
|
|
|
|
|
|
If there is a problem with recovering the state of the actor from the journal, the actor will be
|
|
|
|
|
|
sent a :class:`RecoveryFailure` message that it can choose to handle in ``receiveRecover``. If the
|
|
|
|
|
|
actor doesn't handle the :class:`RecoveryFailure` message it will be stopped.
|
2014-03-24 15:35:54 +01:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#recovery-completed
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
.. _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 persistent actors. 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
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
In order to implement the pattern known as "*command sourcing*" simply call ``persistAsync(cmd)(...)`` right away on all incomming
|
|
|
|
|
|
messages right away, and handle them in the callback.
|
|
|
|
|
|
|
|
|
|
|
|
.. _defer-scala:
|
|
|
|
|
|
|
|
|
|
|
|
Deferring actions until preceeding persist handlers have executed
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
Sometimes when working with ``persistAsync`` you may find that it would be nice to define some actions in terms of
|
|
|
|
|
|
''happens-after the previous ``persistAsync`` handlers have been invoked''. ``PersistentActor`` provides an utility method
|
|
|
|
|
|
called ``defer``, which works similarily to ``persistAsync`` yet does not persist the passed in event. It is recommended to
|
|
|
|
|
|
use it for *read* operations, and actions which do not have corresponding events in your domain model.
|
|
|
|
|
|
|
|
|
|
|
|
Using this method is very similar to the persist family of methods, yet it does **not** persist the passed in event.
|
|
|
|
|
|
It will be kept in memory and used when invoking the handler.
|
2014-03-24 15:35:54 +01:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#defer
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Notice that the ``sender()`` is **safe** to access in the handler callback, and will be pointing to the original sender
|
|
|
|
|
|
of the command for which this ``defer`` handler was called.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
The calling side will get the responses in this (guaranteed) order:
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#defer-caller
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.. _batch-writes:
|
|
|
|
|
|
|
|
|
|
|
|
Batch writes
|
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
|
|
To optimize throughput, a persistent actor internally batches events to be stored under high load before
|
|
|
|
|
|
writing them to the journal (as a single batch). The batch size dynamically grows from 1 under low and moderate loads
|
|
|
|
|
|
to a configurable maximum size (default is ``200``) under high load. When using ``persistAsync`` this increases
|
|
|
|
|
|
the maximum throughput dramatically.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#max-message-batch-size
|
|
|
|
|
|
|
|
|
|
|
|
A new batch write is triggered by a persistent actor as soon as a batch reaches the maximum size or if the journal completed
|
|
|
|
|
|
writing the previous batch. Batch writes are never timer-based which keeps latencies at a minimum.
|
|
|
|
|
|
|
|
|
|
|
|
The batches are also used internally 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 a ``PersistentActor`` will therefore never be done partially (with only a subset of events persisted by a
|
|
|
|
|
|
single command).
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
2013-11-07 10:45:02 +01:00
|
|
|
|
Message deletion
|
|
|
|
|
|
----------------
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
A persistent actor can delete a single message by calling the ``deleteMessage`` method with the sequence number of
|
2013-11-12 09:02:02 +01:00
|
|
|
|
that message as argument. An optional ``permanent`` parameter specifies whether the message shall be permanently
|
|
|
|
|
|
deleted from the journal or only marked as deleted. In both cases, the message won't be replayed. Later extensions
|
|
|
|
|
|
to Akka persistence will allow to replay messages that have been marked as deleted which can be useful for debugging
|
2014-06-25 12:51:21 +02:00
|
|
|
|
purposes, for example. To delete all messages (journaled by a single persistent actor) up to a specified sequence number,
|
|
|
|
|
|
persistent actors should call the ``deleteMessages`` method.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
.. _persistent-views:
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
Persistent Views
|
|
|
|
|
|
================
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
Persistent views can be implemented by extending the ``PersistentView`` trait and implementing the ``receive`` and the ``persistenceId``
|
2014-01-17 06:58:25 +01:00
|
|
|
|
methods.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#view
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
The ``persistenceId`` identifies the persistent actor from which the view receives journaled messages. It is not necessary
|
|
|
|
|
|
the referenced persistent actor is actually running. Views read messages from a persistent actor's journal directly. When a
|
|
|
|
|
|
persistent actor is started later and begins to write new messages, the corresponding view is updated automatically, by
|
2014-01-17 06:58:25 +01:00
|
|
|
|
default.
|
|
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
It is possible to determine if a message was sent from the Journal or from another actor in user-land by calling the ``isPersistent``
|
|
|
|
|
|
method. Having that said, very often you don't need this information at all and can simply apply the same logic to both cases
|
|
|
|
|
|
(skip the ``if isPersistent`` check).
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
Updates
|
|
|
|
|
|
-------
|
|
|
|
|
|
|
|
|
|
|
|
The default update interval of all views of an actor system is configurable:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#auto-update-interval
|
|
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
``PersistentView`` implementation classes may also override the ``autoUpdateInterval`` method to return a custom update
|
2014-01-17 06:58:25 +01:00
|
|
|
|
interval for a specific view class or view instance. Applications may also trigger additional updates at
|
|
|
|
|
|
any time by sending a view an ``Update`` message.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#view-update
|
|
|
|
|
|
|
|
|
|
|
|
If the ``await`` parameter is set to ``true``, messages that follow the ``Update`` request are processed when the
|
|
|
|
|
|
incremental message replay, triggered by that update request, completed. If set to ``false`` (default), messages
|
|
|
|
|
|
following the update request may interleave with the replayed message stream. Automated updates always run with
|
|
|
|
|
|
``await = false``.
|
|
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
Automated updates of all persistent views of an actor system can be turned off by configuration:
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#auto-update
|
|
|
|
|
|
|
|
|
|
|
|
Implementation classes may override the configured default value by overriding the ``autoUpdate`` method. To
|
|
|
|
|
|
limit the number of replayed messages per update request, applications can configure a custom
|
|
|
|
|
|
``akka.persistence.view.auto-update-replay-max`` value or override the ``autoUpdateReplayMax`` method. The number
|
|
|
|
|
|
of replayed messages for manual updates can be limited with the ``replayMax`` parameter of the ``Update`` message.
|
|
|
|
|
|
|
|
|
|
|
|
Recovery
|
|
|
|
|
|
--------
|
|
|
|
|
|
|
2014-06-24 16:57:33 +02:00
|
|
|
|
Initial recovery of persistent views works in the very same way as for a persistent actor (i.e. by sending a ``Recover`` message
|
2014-01-17 06:58:25 +01:00
|
|
|
|
to self). The maximum number of replayed messages during initial recovery is determined by ``autoUpdateReplayMax``.
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Further possibilities to customize initial recovery are explained in section :ref:`recovery`.
|
|
|
|
|
|
|
|
|
|
|
|
.. _persistence-identifiers:
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
|
|
|
|
|
Identifiers
|
|
|
|
|
|
-----------
|
|
|
|
|
|
|
2014-06-26 13:56:01 +02:00
|
|
|
|
A persistent view must have an identifier that doesn't change across different actor incarnations.
|
|
|
|
|
|
The identifier must be defined with the ``viewId`` method.
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
|
The ``viewId`` must differ from the referenced ``persistenceId``, unless :ref:`snapshots` of a view and its
|
2014-06-25 12:51:21 +02:00
|
|
|
|
persistent actor shall be shared (which is what applications usually do not want).
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-05-01 09:05:15 +02:00
|
|
|
|
.. _streams:
|
|
|
|
|
|
|
|
|
|
|
|
Streams
|
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
|
|
**TODO: rename *producer* to *publisher*.**
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
A `Reactive Streams`_ ``Producer`` can be created from a persistent actor's message stream via the ``PersistentFlow``
|
2014-05-01 09:05:15 +02:00
|
|
|
|
extension of the Akka Streams Scala DSL:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#producer-creation
|
|
|
|
|
|
|
|
|
|
|
|
The created ``flow`` object is of type ``Flow[Persistent]`` and can be composed with other flows using ``Flow``
|
|
|
|
|
|
combinators (= methods defined on ``Flow``). Calling the ``toProducer`` method on ``flow`` creates a producer
|
|
|
|
|
|
of type ``Producer[Persistent]``.
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
A persistent message producer only reads from a persistent actor's journal when explicitly requested by downstream
|
|
|
|
|
|
consumers. In order to avoid frequent, fine grained read access to a persistent actor's journal, the producer tries
|
2014-05-01 09:05:15 +02:00
|
|
|
|
to buffer persistent messages in memory from which it serves downstream requests. The maximum buffer size per
|
|
|
|
|
|
producer is configurable with a ``PersistentPublisherSettings`` configuration object.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#producer-buffer-size
|
|
|
|
|
|
|
|
|
|
|
|
Other ``ProducerSettings`` parameters are:
|
|
|
|
|
|
|
|
|
|
|
|
* ``fromSequenceNr``: specifies from which sequence number the persistent message stream shall start (defaults
|
|
|
|
|
|
to ``1L``). Please note that specifying ``fromSequenceNr`` is much more efficient than using the ``drop(Int)``
|
|
|
|
|
|
combinator, especially for larger sequence numbers.
|
|
|
|
|
|
|
|
|
|
|
|
* ``idle``: an optional parameter that specifies how long a producer shall wait after a journal read attempt didn't return
|
|
|
|
|
|
any new persistent messages. If not defined, the producer uses the ``akka.persistence.view.auto-update-interval``
|
|
|
|
|
|
configuration parameter, otherwise, it uses the defined ``idle`` parameter.
|
|
|
|
|
|
|
|
|
|
|
|
Here are two examples how persistent message producers can be connected to downstream consumers using the Akka
|
|
|
|
|
|
Streams Scala DSL and its ``PersistentFlow`` extension.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#producer-examples
|
|
|
|
|
|
|
2013-09-26 09:14:43 +02:00
|
|
|
|
.. _snapshots:
|
|
|
|
|
|
|
|
|
|
|
|
Snapshots
|
|
|
|
|
|
=========
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Snapshots can dramatically reduce recovery times of persistent actors and views. The following discusses snapshots
|
2014-06-24 16:57:33 +02:00
|
|
|
|
in context of persistent actors but this is also applicable to persistent views.
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Persistent actors can save snapshots of internal state by calling the ``saveSnapshot`` method. If saving of a snapshot
|
|
|
|
|
|
succeeds, the persistent actor receives a ``SaveSnapshotSuccess`` message, otherwise a ``SaveSnapshotFailure`` message
|
2013-09-26 09:14:43 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#save-snapshot
|
|
|
|
|
|
|
|
|
|
|
|
where ``metadata`` is of type ``SnapshotMetadata``:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: ../../../akka-persistence/src/main/scala/akka/persistence/Snapshot.scala#snapshot-metadata
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
During recovery, the persistent actor is offered a previously saved snapshot via a ``SnapshotOffer`` message from
|
2013-09-26 09:14:43 +02:00
|
|
|
|
which it can initialize internal state.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#snapshot-offer
|
|
|
|
|
|
|
|
|
|
|
|
The replayed messages that follow the ``SnapshotOffer`` message, if any, are younger than the offered snapshot.
|
2014-06-25 12:51:21 +02:00
|
|
|
|
They finally recover the persistent actor to its current (i.e. latest) state.
|
2013-09-26 09:14:43 +02:00
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
In general, a persistent actor is only offered a snapshot if that persistent actor has previously saved one or more snapshots
|
2013-09-26 09:14:43 +02:00
|
|
|
|
and at least one of these snapshots matches the ``SnapshotSelectionCriteria`` that can be specified for recovery.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#snapshot-criteria
|
|
|
|
|
|
|
|
|
|
|
|
If not specified, they default to ``SnapshotSelectionCriteria.Latest`` which selects the latest (= youngest) snapshot.
|
|
|
|
|
|
To disable snapshot-based recovery, applications should use ``SnapshotSelectionCriteria.None``. A recovery where no
|
|
|
|
|
|
saved snapshot matches the specified ``SnapshotSelectionCriteria`` will replay all journaled messages.
|
|
|
|
|
|
|
2013-11-12 09:02:02 +01:00
|
|
|
|
Snapshot deletion
|
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
A persistent actor can delete individual snapshots by calling the ``deleteSnapshot`` method with the sequence number and the
|
|
|
|
|
|
timestamp of a snapshot as argument. To bulk-delete snapshots matching ``SnapshotSelectionCriteria``, persistent actors should
|
2014-01-17 06:58:25 +01:00
|
|
|
|
use the ``deleteSnapshots`` method.
|
2013-11-12 09:02:02 +01:00
|
|
|
|
|
2013-10-27 08:01:14 +01:00
|
|
|
|
|
2014-02-24 10:34:22 +01:00
|
|
|
|
.. _storage-plugins:
|
|
|
|
|
|
|
2013-10-08 11:46:02 +02:00
|
|
|
|
Storage plugins
|
|
|
|
|
|
===============
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
Storage backends for journals and snapshot stores are pluggable in Akka persistence. The default journal plugin
|
2013-11-25 12:02:29 +01:00
|
|
|
|
writes messages to LevelDB (see :ref:`local-leveldb-journal`). The default snapshot store plugin writes snapshots
|
|
|
|
|
|
as individual files to the local filesystem (see :ref:`local-snapshot-store`). Applications can provide their own
|
|
|
|
|
|
plugins by implementing a plugin API and activate them by configuration. Plugin development requires the following
|
|
|
|
|
|
imports:
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#plugin-imports
|
|
|
|
|
|
|
2014-02-24 10:34:22 +01:00
|
|
|
|
.. _journal-plugin-api:
|
|
|
|
|
|
|
2013-10-08 11:46:02 +02:00
|
|
|
|
Journal plugin API
|
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
|
|
A journal plugin either extends ``SyncWriteJournal`` or ``AsyncWriteJournal``. ``SyncWriteJournal`` is an
|
2014-01-17 06:58:25 +01:00
|
|
|
|
actor that should be extended when the storage backend API only supports synchronous, blocking writes. In this
|
|
|
|
|
|
case, the methods to be implemented are:
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: ../../../akka-persistence/src/main/scala/akka/persistence/journal/SyncWriteJournal.scala#journal-plugin-api
|
|
|
|
|
|
|
|
|
|
|
|
``AsyncWriteJournal`` is an actor that should be extended if the storage backend API supports asynchronous,
|
2014-01-17 06:58:25 +01:00
|
|
|
|
non-blocking writes. In this case, the methods to be implemented are:
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: ../../../akka-persistence/src/main/scala/akka/persistence/journal/AsyncWriteJournal.scala#journal-plugin-api
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
Message replays and sequence number recovery are always asynchronous, therefore, any journal plugin must implement:
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
.. includecode:: ../../../akka-persistence/src/main/scala/akka/persistence/journal/AsyncRecovery.scala#journal-plugin-api
|
2013-10-08 11:46:02 +02:00
|
|
|
|
|
|
|
|
|
|
A journal plugin can be activated with the following minimal configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#journal-plugin-config
|
|
|
|
|
|
|
|
|
|
|
|
The specified plugin ``class`` must have a no-arg constructor. The ``plugin-dispatcher`` is the dispatcher
|
|
|
|
|
|
used for the plugin actor. If not specified, it defaults to ``akka.persistence.dispatchers.default-plugin-dispatcher``
|
|
|
|
|
|
for ``SyncWriteJournal`` plugins and ``akka.actor.default-dispatcher`` for ``AsyncWriteJournal`` plugins.
|
|
|
|
|
|
|
|
|
|
|
|
Snapshot store plugin API
|
|
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
|
|
|
A snapshot store plugin must extend the ``SnapshotStore`` actor and implement the following methods:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: ../../../akka-persistence/src/main/scala/akka/persistence/snapshot/SnapshotStore.scala#snapshot-store-plugin-api
|
|
|
|
|
|
|
|
|
|
|
|
A snapshot store plugin can be activated with the following minimal configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#snapshot-store-plugin-config
|
|
|
|
|
|
|
|
|
|
|
|
The specified plugin ``class`` must have a no-arg constructor. The ``plugin-dispatcher`` is the dispatcher
|
|
|
|
|
|
used for the plugin actor. If not specified, it defaults to ``akka.persistence.dispatchers.default-plugin-dispatcher``.
|
|
|
|
|
|
|
2014-02-24 10:34:22 +01:00
|
|
|
|
.. _pre-packaged-plugins:
|
|
|
|
|
|
|
2013-11-25 12:02:29 +01:00
|
|
|
|
Pre-packaged plugins
|
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
|
|
.. _local-leveldb-journal:
|
|
|
|
|
|
|
|
|
|
|
|
Local LevelDB journal
|
|
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
|
|
|
|
The default journal plugin is ``akka.persistence.journal.leveldb`` which writes messages to a local LevelDB
|
|
|
|
|
|
instance. The default location of the LevelDB files is a directory named ``journal`` in the current working
|
|
|
|
|
|
directory. This location can be changed by configuration where the specified path can be relative or absolute:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#journal-config
|
|
|
|
|
|
|
|
|
|
|
|
With this plugin, each actor system runs its own private LevelDB instance.
|
|
|
|
|
|
|
2013-12-06 12:48:44 +01:00
|
|
|
|
|
|
|
|
|
|
.. _shared-leveldb-journal:
|
|
|
|
|
|
|
2013-11-25 12:02:29 +01:00
|
|
|
|
Shared LevelDB journal
|
|
|
|
|
|
----------------------
|
|
|
|
|
|
|
|
|
|
|
|
A LevelDB instance can also be shared by multiple actor systems (on the same or on different nodes). This, for
|
2014-06-25 12:51:21 +02:00
|
|
|
|
example, allows persistent actors to failover to a backup node and continue using the shared journal instance from the
|
2014-01-17 06:58:25 +01:00
|
|
|
|
backup node.
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
|
|
|
|
A shared LevelDB instance is a single point of failure and should therefore only be used for testing
|
2014-01-25 08:35:06 +01:00
|
|
|
|
purposes. Highly-available, replicated journal are available as `Community plugins`_.
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
A shared LevelDB instance is started by instantiating the ``SharedLeveldbStore`` actor.
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#shared-store-creation
|
|
|
|
|
|
|
|
|
|
|
|
By default, the shared instance writes journaled messages to a local directory named ``journal`` in the current
|
|
|
|
|
|
working directory. The storage location can be changed by configuration:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#shared-store-config
|
|
|
|
|
|
|
|
|
|
|
|
Actor systems that use a shared LevelDB store must activate the ``akka.persistence.journal.leveldb-shared``
|
|
|
|
|
|
plugin.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#shared-journal-config
|
|
|
|
|
|
|
|
|
|
|
|
This plugin must be initialized by injecting the (remote) ``SharedLeveldbStore`` actor reference. Injection is
|
|
|
|
|
|
done by calling the ``SharedLeveldbJournal.setStore`` method with the actor reference as argument.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#shared-store-usage
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
Internal journal commands (sent by persistent actors) are buffered until injection completes. Injection is idempotent
|
2013-11-25 12:02:29 +01:00
|
|
|
|
i.e. only the first injection is used.
|
|
|
|
|
|
|
|
|
|
|
|
.. _local-snapshot-store:
|
|
|
|
|
|
|
|
|
|
|
|
Local snapshot store
|
|
|
|
|
|
--------------------
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
The default snapshot store plugin is ``akka.persistence.snapshot-store.local``. It writes snapshot files to
|
2013-11-25 12:02:29 +01:00
|
|
|
|
the local filesystem. The default storage location is a directory named ``snapshots`` in the current working
|
|
|
|
|
|
directory. This can be changed by configuration where the specified path can be relative or absolute:
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#snapshot-config
|
|
|
|
|
|
|
2014-02-24 10:34:22 +01:00
|
|
|
|
.. _custom-serialization:
|
|
|
|
|
|
|
2013-10-09 13:11:53 +02:00
|
|
|
|
Custom serialization
|
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
|
|
Serialization of snapshots and payloads of ``Persistent`` messages is configurable with Akka's
|
|
|
|
|
|
:ref:`serialization-scala` infrastructure. For example, if an application wants to serialize
|
|
|
|
|
|
|
|
|
|
|
|
* payloads of type ``MyPayload`` with a custom ``MyPayloadSerializer`` and
|
|
|
|
|
|
* snapshots of type ``MySnapshot`` with a custom ``MySnapshotSerializer``
|
|
|
|
|
|
|
|
|
|
|
|
it must add
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceSerializerDocSpec.scala#custom-serializer-config
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
to the application configuration. If not specified, a default serializer is used.
|
2013-10-09 13:11:53 +02:00
|
|
|
|
|
2013-12-06 12:48:44 +01:00
|
|
|
|
Testing
|
|
|
|
|
|
=======
|
|
|
|
|
|
|
|
|
|
|
|
When running tests with LevelDB default settings in ``sbt``, make sure to set ``fork := true`` in your sbt project
|
|
|
|
|
|
otherwise, you'll see an ``UnsatisfiedLinkError``. Alternatively, you can switch to a LevelDB Java port by setting
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#native-config
|
|
|
|
|
|
|
|
|
|
|
|
or
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistencePluginDocSpec.scala#shared-store-native-config
|
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
|
in your Akka configuration. The LevelDB Java port is for testing purposes only.
|
2013-12-06 12:48:44 +01:00
|
|
|
|
|
2013-09-14 14:19:18 +02:00
|
|
|
|
Miscellaneous
|
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
|
|
State machines
|
|
|
|
|
|
--------------
|
|
|
|
|
|
|
2014-06-25 12:51:21 +02:00
|
|
|
|
State machines can be persisted by mixing in the ``FSM`` trait into persistent actors.
|
2013-09-14 14:19:18 +02:00
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/persistence/PersistenceDocSpec.scala#fsm-example
|
2014-03-23 18:39:55 +01:00
|
|
|
|
|
|
|
|
|
|
Configuration
|
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
|
|
There are several configuration properties for the persistence module, please refer
|
|
|
|
|
|
to the :ref:`reference configuration <config-akka-persistence>`.
|
|
|
|
|
|
|