+per #17579 #17617 Introduces EventAdapter

+ 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:
Konrad Malawski 2015-05-29 18:20:51 +02:00
parent 0214d6e14d
commit 7e86dac542
28 changed files with 1534 additions and 119 deletions

View file

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

View file

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