Merge pull request #17828 from ktoso/wip-nested-persist-ktoso
~per #15640 support nested persist calls
This commit is contained in:
commit
83e931ea7e
10 changed files with 752 additions and 46 deletions
|
|
@ -41,7 +41,7 @@ public class PersistenceDocTest {
|
|||
|
||||
private void recover() {
|
||||
//#recover-explicit
|
||||
persistentActor.tell(Recover.create(), getSelf());
|
||||
persistentActor.tell(Recover.create(), self());
|
||||
//#recover-explicit
|
||||
}
|
||||
}
|
||||
|
|
@ -64,7 +64,7 @@ public class PersistenceDocTest {
|
|||
//#recover-on-start-custom
|
||||
@Override
|
||||
public void preStart() {
|
||||
getSelf().tell(Recover.create(457L), getSelf());
|
||||
self().tell(Recover.create(457L), self());
|
||||
}
|
||||
//#recover-on-start-custom
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ public class PersistenceDocTest {
|
|||
abstract class MyPersistentActor1 extends UntypedPersistentActor {
|
||||
//#recover-fully-disabled
|
||||
@Override
|
||||
public void preStart() { getSelf().tell(Recover.create(0L), getSelf()); }
|
||||
public void preStart() { self().tell(Recover.create(0L), self()); }
|
||||
//#recover-fully-disabled
|
||||
}
|
||||
};
|
||||
|
|
@ -227,7 +227,7 @@ public class PersistenceDocTest {
|
|||
if (message instanceof Msg) {
|
||||
Msg msg = (Msg) message;
|
||||
// ...
|
||||
getSender().tell(new Confirm(msg.deliveryId), getSelf());
|
||||
getSender().tell(new Confirm(msg.deliveryId), self());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
@ -324,7 +324,7 @@ public class PersistenceDocTest {
|
|||
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
sender().tell(msg, getSelf());
|
||||
sender().tell(msg, self());
|
||||
|
||||
persistAsync(String.format("evt-%s-1", msg), new Procedure<String>(){
|
||||
@Override
|
||||
|
|
@ -376,7 +376,7 @@ public class PersistenceDocTest {
|
|||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, getSelf());
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -408,6 +408,140 @@ public class PersistenceDocTest {
|
|||
};
|
||||
|
||||
static Object o11 = new Object() {
|
||||
|
||||
class MyPersistentActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
//#nested-persist-persist
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
final Procedure<String> outer1Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persist(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
final Procedure<String> outer2Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persist(String.format("%s-inner-2", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
|
||||
persist(String.format("%s-outer-1", msg), outer1Callback);
|
||||
persist(String.format("%s-outer-2", msg), outer2Callback);
|
||||
}
|
||||
//#nested-persist-persist
|
||||
|
||||
void usage(ActorRef persistentActor) {
|
||||
//#nested-persist-persist-caller
|
||||
persistentActor.tell("a", self());
|
||||
persistentActor.tell("b", self());
|
||||
|
||||
// order of received messages:
|
||||
// a
|
||||
// a-outer-1
|
||||
// a-outer-2
|
||||
// a-inner-1
|
||||
// a-inner-2
|
||||
// and only then process "b"
|
||||
// b
|
||||
// b-outer-1
|
||||
// b-outer-2
|
||||
// b-inner-1
|
||||
// b-inner-2
|
||||
|
||||
//#nested-persist-persist-caller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyPersistAsyncActor extends UntypedPersistentActor {
|
||||
@Override
|
||||
public String persistenceId() {
|
||||
return "my-stable-persistence-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveRecover(Object msg) {
|
||||
// handle recovery here
|
||||
}
|
||||
|
||||
//#nested-persistAsync-persistAsync
|
||||
@Override
|
||||
public void onReceiveCommand(Object msg) {
|
||||
final Procedure<String> replyToSender = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
}
|
||||
};
|
||||
|
||||
final Procedure<String> outer1Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persistAsync(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
final Procedure<String> outer2Callback = new Procedure<String>() {
|
||||
@Override
|
||||
public void apply(String event) throws Exception {
|
||||
sender().tell(event, self());
|
||||
persistAsync(String.format("%s-inner-1", msg), replyToSender);
|
||||
}
|
||||
};
|
||||
|
||||
persistAsync(String.format("%s-outer-1", msg), outer1Callback);
|
||||
persistAsync(String.format("%s-outer-2", msg), outer2Callback);
|
||||
}
|
||||
//#nested-persistAsync-persistAsync
|
||||
|
||||
|
||||
void usage(ActorRef persistentActor) {
|
||||
//#nested-persistAsync-persistAsync-caller
|
||||
persistentActor.tell("a", ActorRef.noSender());
|
||||
persistentActor.tell("b", ActorRef.noSender());
|
||||
|
||||
// order of received messages:
|
||||
// a
|
||||
// b
|
||||
// a-outer-1
|
||||
// a-outer-2
|
||||
// b-outer-1
|
||||
// b-outer-2
|
||||
// a-inner-1
|
||||
// a-inner-2
|
||||
// b-inner-1
|
||||
// b-inner-2
|
||||
|
||||
// which can be seen as the following causal relationship:
|
||||
// a -> a-outer-1 -> a-outer-2 -> a-inner-1 -> a-inner-2
|
||||
// b -> b-outer-1 -> b-outer-2 -> b-inner-1 -> b-inner-2
|
||||
|
||||
//#nested-persistAsync-persistAsync-caller
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static Object o12 = new Object() {
|
||||
//#view
|
||||
class MyView extends UntypedPersistentView {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ The ordering between events is still guaranteed ("evt-b-1" will be sent after "e
|
|||
.. _defer-java-lambda:
|
||||
|
||||
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
|
||||
|
|
@ -270,6 +270,41 @@ of the command for which this ``defer`` handler was called.
|
|||
The callback will not be invoked if the actor is restarted (or stopped) in between the call to
|
||||
``defer`` and the journal has processed and confirmed all preceding writes.
|
||||
|
||||
.. _nested-persist-calls-lambda:
|
||||
|
||||
Nested persist calls
|
||||
--------------------
|
||||
It is possible to call ``persist`` and ``persistAsync`` inside their respective callback blocks and they will properly
|
||||
retain both the thread safety (including the right value of ``sender()``) as well as stashing guarantees.
|
||||
|
||||
In general it is encouraged to create command handlers which do not need to resort to nested event persisting,
|
||||
however there are situations where it may be useful. It is important to understand the ordering of callback execution in
|
||||
those situations, as well as their implication on the stashing behaviour (that ``persist()`` enforces). In the following
|
||||
example two persist calls are issued, and each of them issues another persist inside its callback:
|
||||
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/doc/LambdaPersistenceDocTest.java#nested-persist-persist
|
||||
|
||||
When sending two commands to this ``PersistentActor``, the persist handlers will be executed in the following order:
|
||||
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/doc/LambdaPersistenceDocTest.java#nested-persist-persist-caller
|
||||
|
||||
First the "outer layer" of persist calls is issued and their callbacks applied, after these have successfully completed
|
||||
the inner callbacks will be invoked (once the events they are persisting have been confirmed to be persisted by the journal).
|
||||
And only after all these handlers have been successfully invoked, the next command will delivered to the persistent Actor.
|
||||
In other words, the stashing of incoming commands that is guaranteed by initially calling ``persist()`` on the outer layer
|
||||
is extended until all nested ``persist`` callbacks have been handled.
|
||||
|
||||
It is also possible to nest ``persistAsync`` calls, using the same pattern:
|
||||
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/doc/LambdaPersistenceDocTest.java#nested-persistAsync-persistAsync
|
||||
|
||||
In this case no stashing is happening, yet the events are still persisted and callbacks executed in the expected order:
|
||||
|
||||
.. includecode:: ../../../akka-samples/akka-sample-persistence-java-lambda/src/main/java/doc/LambdaPersistenceDocTest.java#nested-persistAsync-persistAsync-caller
|
||||
|
||||
While it is possible to nest mixed ``persist`` and ``persistAsync`` with keeping their respective semantics
|
||||
it is not a recommended practice as it may lead to overly complex nesting.
|
||||
|
||||
Failures
|
||||
--------
|
||||
|
||||
|
|
|
|||
|
|
@ -273,6 +273,41 @@ of the command for which this ``defer`` handler was called.
|
|||
The callback will not be invoked if the actor is restarted (or stopped) in between the call to
|
||||
``defer`` and the journal has processed and confirmed all preceding writes.
|
||||
|
||||
.. _nested-persist-calls-java:
|
||||
|
||||
Nested persist calls
|
||||
--------------------
|
||||
It is possible to call ``persist`` and ``persistAsync`` inside their respective callback blocks and they will properly
|
||||
retain both the thread safety (including the right value of ``sender()``) as well as stashing guarantees.
|
||||
|
||||
In general it is encouraged to create command handlers which do not need to resort to nested event persisting,
|
||||
however there are situations where it may be useful. It is important to understand the ordering of callback execution in
|
||||
those situations, as well as their implication on the stashing behaviour (that ``persist()`` enforces). In the following
|
||||
example two persist calls are issued, and each of them issues another persist inside its callback:
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocTest.java#nested-persist-persist
|
||||
|
||||
When sending two commands to this ``PersistentActor``, the persist handlers will be executed in the following order:
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocTest.java#nested-persist-persist-caller
|
||||
|
||||
First the "outer layer" of persist calls is issued and their callbacks applied, after these have successfully completed
|
||||
the inner callbacks will be invoked (once the events they are persisting have been confirmed to be persisted by the journal).
|
||||
And only after all these handlers have been successfully invoked, the next command will delivered to the persistent Actor.
|
||||
In other words, the stashing of incoming commands that is guaranteed by initially calling ``persist()`` on the outer layer
|
||||
is extended until all nested ``persist`` callbacks have been handled.
|
||||
|
||||
It is also possible to nest ``persistAsync`` calls, using the same pattern:
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocTest.java#nested-persistAsync-persistAsync
|
||||
|
||||
In this case no stashing is happening, yet the events are still persisted and callbacks executed in the expected order:
|
||||
|
||||
.. includecode:: code/docs/persistence/PersistenceDocTest.java#nested-persistAsync-persistAsync-caller
|
||||
|
||||
While it is possible to nest mixed ``persist`` and ``persistAsync`` with keeping their respective semantics
|
||||
it is not a recommended practice as it may lead to overly complex nesting.
|
||||
|
||||
Failures
|
||||
--------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue