+ per plugin scoped adapters + could be swapped during runtime +per EventAdapter now has manifest and is configurable ai la serializers + json examples in docs + including "completely manual" example in case one wants to add metadata TO the persisted event + better error reporting when misconfigured bindings + manifest is handled by in memory plugin - did not check if it works with LevelDB plugin yet > TODO: json example uses Gson, as that's simplest to do, can we use +per allows 1:n adapters, multiple adapters can be bound to 1 class
This commit is contained in:
parent
0214d6e14d
commit
7e86dac542
28 changed files with 1534 additions and 119 deletions
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.persistence;
|
||||
|
||||
import akka.persistence.journal.EventAdapter;
|
||||
import akka.persistence.journal.EventSeq;
|
||||
|
||||
public class PersistenceEventAdapterDocTest {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static
|
||||
//#identity-event-adapter
|
||||
class MyEventAdapter extends EventAdapter {
|
||||
@Override
|
||||
public String manifest(Object event) {
|
||||
return ""; // if no manifest needed, return ""
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJournal(Object event) {
|
||||
return event; // identity
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventSeq fromJournal(Object event, String manifest) {
|
||||
return EventSeq.single(event); // identity
|
||||
}
|
||||
}
|
||||
//#identity-event-adapter
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ The ordering between events is still guaranteed ("evt-b-1" will be sent after "e
|
|||
.. _defer-java:
|
||||
|
||||
Deferring actions until preceding 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
|
||||
|
|
@ -503,6 +503,54 @@ not accept more messages and it will throw ``AtLeastOnceDelivery.MaxUnconfirmedM
|
|||
The default value can be configured with the ``akka.persistence.at-least-once-delivery.max-unconfirmed-messages``
|
||||
configuration key. The method can be overridden by implementation classes to return non-default values.
|
||||
|
||||
.. _event-adapters-java:
|
||||
|
||||
Event Adapters
|
||||
==============
|
||||
|
||||
.. note::
|
||||
|
||||
Complete documentation featuring use-cases and implementation examples for this feature will follow shortly.
|
||||
|
||||
In long running projects using event sourcing sometimes the need arrises to detach the data model from the domain model
|
||||
completely.
|
||||
|
||||
Event Adapters help in situations where:
|
||||
|
||||
- **Version Migration** – existing events stored in *Version 1* should be "upcasted" to a new *Version 2* representation,
|
||||
and the process of doing so involves actual code, not just changes on the serialization layer. For these scenarios
|
||||
the ``toJournal`` function is usually an identity function, however the ``fromJournal`` is implemented as
|
||||
``v1.Event=>v2.Event``, performing the neccessary mapping inside the fromJournal method.
|
||||
This technique is sometimes refered to as "upcasting" in other CQRS libraries.
|
||||
- **Separating Domain and Data models** – thanks to EventAdapters it is possible to completely separate the domain model
|
||||
from the model used to persist data in the Journals. For example one may want to use case classes in the
|
||||
domain model, however persist their protocol-buffer (or any other binary serialization format) counter-parts to the Journal.
|
||||
A simple ``toJournal:MyModel=>MyDataModel`` and ``fromJournal:MyDataModel=>MyModel`` adapter can be used to implement this feature.
|
||||
- **Journal Specialized Data Types** – exposing data types understood by the underlying Journal, for example for data stores which
|
||||
understand JSON it is possible to write an EventAdapter ``toJournal:Any=>JSON`` such that the Journal can *directly* store the
|
||||
json instead of serializing the object to its binary representation.
|
||||
|
||||
Implementing an EventAdapter is rather stright forward:
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceEventAdapterDocTest.java#identity-event-adapter
|
||||
|
||||
Then in order for it to be used on events coming to and from the journal you must bind it using the below configuration syntax:
|
||||
|
||||
.. includecode:: ../scala/code/docs/persistence/PersistenceEventAdapterDocSpec.scala#event-adapters-config
|
||||
|
||||
It is possible to bind multiple adapters to one class *for recovery*, in which case the ``fromJournal`` methods of all
|
||||
bound adapters will be applied to a given matching event (in order of definition in the configuration). Since each adapter may
|
||||
return from ``0`` to ``n`` adapted events (called as ``EventSeq``), each adapter can investigate the event and if it should
|
||||
indeed adapt it return the adapted event(s) for it, other adapters which do not have anything to contribute during this
|
||||
adaptation simply return ``EventSeq.empty``. The adapted events are then delivered in-order to the ``PersistentActor`` during replay.
|
||||
|
||||
.. note::
|
||||
More advanced techniques utilising advanced binary serialization formats such as protocol buffers or kryo / thrift / avro
|
||||
will be documented very soon. These schema evolutions often may need to reach into the serialization layer, however
|
||||
are much more powerful in terms of flexibly removing unused/deprecated classes from your classpath etc.
|
||||
|
||||
|
||||
|
||||
Storage plugins
|
||||
===============
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue